diff options
321 files changed, 9069 insertions, 11734 deletions
diff --git a/.travis.yml b/.travis.yml index 8a6f80002b..7bf968ba4c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,15 +47,6 @@ matrix: - &linux_deps [libasound2-dev, libgl1-mesa-dev, libglu1-mesa-dev, libx11-dev, libxcursor-dev, libxi-dev, libxinerama-dev, libxrandr-dev] - &linux_mono_deps [mono-devel, msbuild, nuget] - coverity_scan: - project: - name: "godotengine/godot" - description: "Godot Engine Coverity scans" - notification_email: coverity@godotengine.org - build_command_prepend: "" - build_command: "scons p=x11 -j2 $OPTIONS" - branch_pattern: coverity_scan - - name: Linux export template (release, Clang) stage: build env: PLATFORM=x11 TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes" diff --git a/core/error_macros.h b/core/error_macros.h index 6d17fd2cb5..00e830f73a 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -111,6 +111,13 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li #define GENERATE_TRAP __builtin_trap(); #endif +// Used to strip debug messages in release mode +#ifdef DEBUG_ENABLED +#define DEBUG_STR(m_msg) m_msg +#else +#define DEBUG_STR(m_msg) "" +#endif + // (*): See https://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for #define ERR_FAIL_INDEX(m_index, m_size) \ @@ -121,12 +128,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } while (0); // (*) -#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ - return; \ - } \ +#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ + do { \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return; \ + } \ } while (0); // (*) /** An index has failed if m_index<0 or m_index >=m_size, the function exits. @@ -142,12 +149,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } while (0); // (*) -#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ - return m_retval; \ - } \ +#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ + do { \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } while (0); // (*) /** An index has failed if m_index >=m_size, the function exits. @@ -163,12 +170,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } while (0); // (*) -#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg); \ - return m_retval; \ - } \ +#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ + do { \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } while (0); // (*) /** Use this one if there is no sensible fallback, that is, the error is unrecoverable. @@ -202,12 +209,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ - { \ - if (unlikely(!m_param)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null.", m_msg); \ - return; \ - } \ +#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ + { \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null.", DEBUG_STR(m_msg)); \ + return; \ + } \ } #define ERR_FAIL_NULL_V(m_param, m_retval) \ @@ -218,12 +225,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ - { \ - if (unlikely(!m_param)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null.", m_msg); \ - return m_retval; \ - } \ +#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ + { \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null.", DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -238,12 +245,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true.", m_msg); \ - return; \ - } \ +#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true.", DEBUG_STR(m_msg)); \ + return; \ + } \ } /** Use this one if there is no sensible fallback, that is, the error is unrecoverable. @@ -257,12 +264,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define CRASH_COND_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition ' " _STR(m_cond) " ' is true.", m_msg); \ - GENERATE_TRAP \ - } \ +#define CRASH_COND_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition ' " _STR(m_cond) " ' is true.", DEBUG_STR(m_msg)); \ + GENERATE_TRAP \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -279,12 +286,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. returned: " _STR(m_retval), m_msg); \ - return m_retval; \ - } \ +#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. returned: " _STR(m_retval), DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -299,12 +306,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define ERR_CONTINUE_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Continuing..:", m_msg); \ - continue; \ - } \ +#define ERR_CONTINUE_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Continuing..:", DEBUG_STR(m_msg)); \ + continue; \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -319,12 +326,12 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } \ } -#define ERR_BREAK_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:", m_msg); \ - break; \ - } \ +#define ERR_BREAK_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:", DEBUG_STR(m_msg)); \ + break; \ + } \ } /** Print an error string and return @@ -336,10 +343,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li return; \ } -#define ERR_FAIL_MSG(m_msg) \ - { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed.", m_msg); \ - return; \ +#define ERR_FAIL_MSG(m_msg) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed.", DEBUG_STR(m_msg)); \ + return; \ } /** Print an error string and return with value @@ -351,10 +358,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li return m_value; \ } -#define ERR_FAIL_V_MSG(m_value, m_msg) \ - { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_value), m_msg); \ - return m_value; \ +#define ERR_FAIL_V_MSG(m_value, m_msg) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_value), DEBUG_STR(m_msg)); \ + return m_value; \ } /** Use this one if there is no sensible fallback, that is, the error is unrecoverable. @@ -366,10 +373,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li GENERATE_TRAP \ } -#define CRASH_NOW_MSG(m_msg) \ - { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/Function Failed.", m_msg); \ - GENERATE_TRAP \ +#define CRASH_NOW_MSG(m_msg) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/Function Failed.", DEBUG_STR(m_msg)); \ + GENERATE_TRAP \ } /** Print an error string. diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 1f685aab81..cecbce90b3 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -783,15 +783,6 @@ Enables or disabled internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). Only useful for advanced uses to manipulate built-in nodes' behaviour. </description> </method> - <method name="set_process_priority"> - <return type="void"> - </return> - <argument index="0" name="priority" type="int"> - </argument> - <description> - Sets the node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes with a higher process priority will have their processing callbacks executed first. - </description> - </method> <method name="set_process_unhandled_input"> <return type="void"> </return> @@ -847,6 +838,9 @@ <member name="pause_mode" type="int" setter="set_pause_mode" getter="get_pause_mode" enum="Node.PauseMode" default="0"> Pause mode. How the node will behave if the [SceneTree] is paused. </member> + <member name="process_priority" type="int" setter="set_process_priority" getter="get_process_priority" default="0"> + The node's priority in the execution order of the enabled processing callbacks (i.e. [constant NOTIFICATION_PROCESS], [constant NOTIFICATION_PHYSICS_PROCESS] and their internal counterparts). Nodes with a higher process priority will have their processing callbacks executed first. + </member> </members> <signals> <signal name="ready"> diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 5deee941da..0310068a90 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -7,6 +7,19 @@ A pre-parsed relative or absolute path in a scene tree, for use with [method Node.get_node] and similar functions. It can reference a node, a resource within a node, or a property of a node or resource. For instance, [code]"Path2D/PathFollow2D/Sprite:texture:size"[/code] would refer to the [code]size[/code] property of the [code]texture[/code] resource on the node named [code]"Sprite"[/code] which is a child of the other named nodes in the path. You will usually just pass a string to [method Node.get_node] and it will be automatically converted, but you may occasionally want to parse a path ahead of time with [NodePath] or the literal syntax [code]@"path"[/code]. Exporting a [NodePath] variable will give you a node selection widget in the properties panel of the editor, which can often be useful. A [NodePath] is composed of a list of slash-separated node names (like a filesystem path) and an optional colon-separated list of "subnames" which can be resources or properties. + Some examples of NodePaths include the following: + [codeblock] + # No leading slash means it is relative to the current node. + @"A" # Immediate child A + @"A/B" # A's child B + @"." # The current node. + @".." # The parent node. + @"../C" # A sibling node C. + # A leading slash means it is absolute from the SceneTree. + @"/root" # Equivalent to get_tree().get_root(). + @"/root/Main" # If your main scene's root node were named "Main". + @"/root/MyAutoload" # If you have an autoloaded node or scene. + [/codeblock] </description> <tutorials> </tutorials> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index e14a3b3759..bf22b865d3 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -194,7 +194,7 @@ </return> <description> Reloads the currently active scene. - Returns an [enum Error] code as described in [method change_scene], with the addition of [constant ERR_UNCONFIGURED] if no [member current_scene] was defined yet. + Returns [constant OK] on success, [constant ERR_UNCONFIGURED] if no [member current_scene] was defined yet, [constant ERR_CANT_OPEN] if [member current_scene] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if the scene cannot be instantiated. </description> </method> <method name="set_auto_accept_quit"> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index e0a4a24299..f5597d89e5 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -744,7 +744,14 @@ Splits the string by a [code]delimiter[/code] string and returns an array of the substrings, starting from right. The splits in the returned array are sorted in the same order as the original string, from left to right. If [code]maxsplit[/code] is specified, it defines the number of splits to do from the right up to [code]maxsplit[/code]. The default value of 0 means that all items are split, thus giving the same result as [method split]. - For example, [code]"One,Two,Three,Four"[/code] will return [code]["Three","Four"][/code] if split by [code]","[/code] with a [code]maxsplit[/code] value of 2. + Example: + [codeblock] + var some_string = "One,Two,Three,Four" + var some_array = some_string.rsplit(",", true, 1) + print(some_array.size()) # Prints 2 + print(some_array[0]) # Prints "Four" + print(some_array[1]) # Prints "Three,Two,One" + [/codeblock] </description> </method> <method name="rstrip"> @@ -805,7 +812,14 @@ <description> Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of 0 means that all items are split. - For example, [code]"One,Two,Three"[/code] will return [code]["One","Two"][/code] if split by [code]","[/code] with a [code]maxsplit[/code] value of 2. + Example: + [codeblock] + var some_string = "One,Two,Three,Four" + var some_array = some_string.split(",", true, 1) + print(some_array.size()) # Prints 2 + print(some_array[0]) # Prints "One" + print(some_array[1]) # Prints "Two,Three,Four" + [/codeblock] </description> </method> <method name="split_floats"> diff --git a/doc/classes/VisualServer.xml b/doc/classes/VisualServer.xml index 28365c213b..895aba2473 100644 --- a/doc/classes/VisualServer.xml +++ b/doc/classes/VisualServer.xml @@ -4255,10 +4255,10 @@ Multisample antialiasing is set to 16×. </constant> <constant name="VIEWPORT_MSAA_EXT_2X" value="5" enum="ViewportMSAA"> - Multisample antialiasing is set to 2× on external texture. Special mode for GLES2 VR for the Oculus Quest. + Multisample antialiasing is set to 2× on external texture. Special mode for GLES2 Android VR (Oculus Quest and Go). </constant> <constant name="VIEWPORT_MSAA_EXT_4X" value="6" enum="ViewportMSAA"> - Multisample antialiasing is set to 4× on external texture. Special mode for GLES2 VR for the Oculus Quest. + Multisample antialiasing is set to 4× on external texture. Special mode for GLES2 Android VR (Oculus Quest and Go). </constant> <constant name="VIEWPORT_USAGE_2D" value="0" enum="ViewportUsage"> The Viewport does not render 3D but samples. diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index e34705f7b7..325f2d6707 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -291,6 +291,10 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights, const int *p_bones) { glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif uint32_t buffer_ofs = 0; @@ -339,6 +343,11 @@ void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_coun } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif + if (storage->config.support_32_bits_indices) { //should check for glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); @@ -358,6 +367,10 @@ void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_coun void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif uint32_t buffer_ofs = 0; @@ -435,6 +448,10 @@ void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_v } glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), buffer_data); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL); @@ -883,7 +900,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur } glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * (16 + 16) * 2, buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, buffer, GL_DYNAMIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); @@ -2034,6 +2051,8 @@ void RasterizerCanvasGLES2::initialize() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + data.polygon_index_buffer_size = index_size; } // ninepatch buffers diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index ab636dca71..ba636a9763 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -65,6 +65,7 @@ public: GLuint polygon_index_buffer; uint32_t polygon_buffer_size; + uint32_t polygon_index_buffer_size; GLuint ninepatch_vertices; GLuint ninepatch_elements; diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 6bcda62e7f..bc47fb46f5 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -2342,9 +2342,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (accum_pass) { //accum pass force pass blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; - if (rebind_light && light && light->light_ptr->negative) { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + if (light && light->light_ptr->negative) { blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB; } } @@ -2704,7 +2702,7 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C } glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector3) * 8, vertices); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, vertices, GL_DYNAMIC_DRAW); // bind sky vertex array.... glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 82cb1ef90b..147bab9d1f 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -4583,13 +4583,24 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { GLuint color_internal_format; GLuint color_format; GLuint color_type = GL_UNSIGNED_BYTE; + Image::Format image_format; if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { +#ifdef GLES_OVER_GL + color_internal_format = GL_RGBA8; +#else color_internal_format = GL_RGBA; +#endif color_format = GL_RGBA; + image_format = Image::FORMAT_RGBA8; } else { +#ifdef GLES_OVER_GL + color_internal_format = GL_RGB8; +#else color_internal_format = GL_RGB; +#endif color_format = GL_RGB; + image_format = Image::FORMAT_RGB8; } rt->used_dof_blur_near = false; @@ -4676,10 +4687,10 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { return; } - texture->format = Image::FORMAT_RGBA8; - texture->gl_format_cache = GL_RGBA; + texture->format = image_format; + texture->gl_format_cache = color_format; texture->gl_type_cache = GL_UNSIGNED_BYTE; - texture->gl_internal_format_cache = GL_RGBA; + texture->gl_internal_format_cache = color_internal_format; texture->tex_id = rt->color; texture->width = rt->width; texture->alloc_width = rt->width; diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index edffe852a2..55d16a6c2e 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -128,7 +128,7 @@ void RasterizerCanvasGLES3::light_internal_update(RID p_rid, Light *p_light) { li->ubo_data.shadow_distance_mult = (p_light->radius_cache * 1.1); glBindBuffer(GL_UNIFORM_BUFFER, li->ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightInternal::UBOData), &li->ubo_data); + glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInternal::UBOData), &li->ubo_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); } @@ -326,6 +326,12 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun glBindVertexArray(data.polygon_buffer_pointer_array); glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffers to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif + uint32_t buffer_ofs = 0; //vertex @@ -417,6 +423,12 @@ void RasterizerCanvasGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count glBindVertexArray(data.polygon_buffer_pointer_array); glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffers to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif + uint32_t buffer_ofs = 0; //vertex @@ -508,6 +520,11 @@ void RasterizerCanvasGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_v } glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); +#ifndef GLES_OVER_GL + // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData + glBufferData(GL_ARRAY_BUFFER, data.polygon_buffer_size, NULL, GL_DYNAMIC_DRAW); +#endif + //TODO the below call may need to be replaced with: glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4 * sizeof(float), &b[0]); glBufferSubData(GL_ARRAY_BUFFER, 0, p_points * stride * 4, &b[0]); glBindVertexArray(data.polygon_buffer_quad_arrays[version]); glDrawArrays(prim[p_points], 0, p_points); @@ -1882,7 +1899,7 @@ void RasterizerCanvasGLES3::reset_canvas() { state.canvas_item_ubo_data.time = storage->frame.time[0]; glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data); + glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); state.canvas_texscreen_used = false; @@ -2109,6 +2126,8 @@ void RasterizerCanvasGLES3::initialize() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); //allocate max size glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + data.polygon_index_buffer_size = index_size; } store_transform(Transform(), state.canvas_item_ubo_data.projection_matrix); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index bf5ef30820..382b1e5640 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -64,6 +64,7 @@ public: GLuint particle_quad_array; uint32_t polygon_buffer_size; + uint32_t polygon_index_buffer_size; } data; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index f52fd00dd2..9815936d1e 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2551,7 +2551,7 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C } glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector3) * 8, vertices); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, vertices, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind glBindVertexArray(state.sky_array); @@ -2691,7 +2691,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr } glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(State::SceneDataUBO), &state.ubo_data); + glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.ubo_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); //fill up environment @@ -2699,7 +2699,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr store_transform(sky_orientation * p_cam_transform, state.env_radiance_data.transform); glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_data); + glBufferData(GL_UNIFORM_BUFFER, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); } @@ -2809,7 +2809,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform } glBindBuffer(GL_UNIFORM_BUFFER, state.directional_ubo); - glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightDataUBO), &ubo_data); + glBufferData(GL_UNIFORM_BUFFER, sizeof(LightDataUBO), &ubo_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); directional_light = li; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index e40164ad87..71a3a79eb3 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -3216,7 +3216,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { } glBindBuffer(GL_UNIFORM_BUFFER, material->ubo_id); - glBufferSubData(GL_UNIFORM_BUFFER, 0, material->ubo_size, local_ubo); + glBufferData(GL_UNIFORM_BUFFER, material->ubo_size, local_ubo, GL_STATIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); } diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 33f833afa4..40aa9a28b2 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -2026,7 +2026,7 @@ void AnimationTrackEdit::_notification(int p_what) { float offset = animation->track_get_key_time(track, i) - timeline->get_value(); if (editor->is_key_selected(track, i) && editor->is_moving_selection()) { - offset = editor->snap_time(offset + editor->get_moving_selection_offset()); + offset = editor->snap_time(offset + editor->get_moving_selection_offset(), true); } offset = offset * scale + limit; if (i < animation->track_get_key_count(track) - 1) { @@ -5703,7 +5703,7 @@ void AnimationTrackEditor::_selection_changed() { } } -float AnimationTrackEditor::snap_time(float p_value) { +float AnimationTrackEditor::snap_time(float p_value, bool p_relative) { if (is_snap_enabled()) { @@ -5713,7 +5713,12 @@ float AnimationTrackEditor::snap_time(float p_value) { else snap_increment = step->get_value(); - p_value = Math::stepify(p_value, snap_increment); + if (p_relative) { + double rel = Math::fmod(timeline->get_value(), snap_increment); + p_value = Math::stepify(p_value + rel, snap_increment) - rel; + } else { + p_value = Math::stepify(p_value, snap_increment); + } } return p_value; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index fd28d8f4d1..ef6a769196 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -521,7 +521,7 @@ public: bool is_moving_selection() const; bool is_snap_enabled() const; float get_moving_selection_offset() const; - float snap_time(float p_value); + float snap_time(float p_value, bool p_relative = false); bool is_grouping_tracks(); MenuButton *get_edit_menu(); diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 1a821ddd02..16780a795f 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -108,6 +108,8 @@ void FindReplaceBar::_notification(int p_what) { hide_button->set_hover_texture(get_icon("Close", "EditorIcons")); hide_button->set_pressed_texture(get_icon("Close", "EditorIcons")); hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size()); + } else if (p_what == NOTIFICATION_THEME_CHANGED) { + matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); } } @@ -328,7 +330,7 @@ void FindReplaceBar::_update_matches_label() { } else { matches_label->show(); - matches_label->add_color_override("font_color", results_count > 0 ? Color(1, 1, 1) : EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count)); } } @@ -1443,6 +1445,9 @@ void CodeTextEditor::_update_font() { text_editor->add_font_override("font", get_font("source", "EditorFonts")); + error->add_font_override("font", get_font("status_source", "EditorFonts")); + error->add_color_override("font_color", get_color("error_color", "Editor")); + Ref<Font> status_bar_font = get_font("status_source", "EditorFonts"); error->add_font_override("font", status_bar_font); int count = status_bar->get_child_count(); @@ -1677,8 +1682,6 @@ CodeTextEditor::CodeTextEditor() { error = memnew(Label); scroll->add_child(error); error->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); - error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); - error->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); error->set_mouse_filter(MOUSE_FILTER_STOP); error->connect("gui_input", this, "_error_pressed"); find_replace_bar->connect("error", error, "set_text"); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index dd49e38d7f..4f7432cd65 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1716,6 +1716,7 @@ void FindBar::_notification(int p_what) { hide_button->set_hover_texture(get_icon("Close", "EditorIcons")); hide_button->set_pressed_texture(get_icon("Close", "EditorIcons")); hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size()); + matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -1802,7 +1803,7 @@ void FindBar::_update_matches_label() { } else { matches_label->show(); - matches_label->add_color_override("font_color", results_count > 0 ? Color(1, 1, 1) : EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + matches_label->add_color_override("font_color", results_count > 0 ? get_color("font_color", "Label") : get_color("error_color", "Editor")); matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count)); } } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 0e373a5deb..ef382c0a19 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -6230,7 +6230,7 @@ EditorNode::EditorNode() { pause_button->set_toggle_mode(true); pause_button->set_icon(gui_base->get_icon("Pause", "EditorIcons")); pause_button->set_focus_mode(Control::FOCUS_NONE); - pause_button->set_tooltip(TTR("Pause the scene")); + pause_button->set_tooltip(TTR("Pause the scene execution for debugging.")); pause_button->set_disabled(true); play_hb->add_child(pause_button); #ifdef OSX_ENABLED diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index a3a02dbd4c..87e8a53e94 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -727,6 +727,7 @@ static Dictionary _get_builtin_script_templates() { templates["no_comments.gd"] = "extends %BASE%\n" "\n" + "\n" "func _ready()%VOID_RETURN%:\n" "%TS%pass\n"; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 7170ce30cc..fcbd68a60f 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -3671,7 +3671,7 @@ void CanvasItemEditor::_notification(int p_what) { int nb_having_pivot = 0; // Update the viewport if the canvas_item changes - List<CanvasItem *> selection = _get_edited_canvas_items(); + List<CanvasItem *> selection = _get_edited_canvas_items(true); for (List<CanvasItem *>::Element *E = selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); @@ -3971,9 +3971,9 @@ void CanvasItemEditor::_update_scrollbars() { updating_scroll = true; // Move the zoom buttons - Point2 zoom_hb_begin = Point2(5, 5); - zoom_hb_begin += (show_rulers) ? Point2(RULER_WIDTH, RULER_WIDTH) : Point2(); - zoom_hb->set_begin(zoom_hb_begin); + Point2 controls_vb_begin = Point2(5, 5); + controls_vb_begin += (show_rulers) ? Point2(RULER_WIDTH, RULER_WIDTH) : Point2(); + controls_vb->set_begin(controls_vb_begin); // Move and resize the scrollbars Size2 size = viewport->get_size(); @@ -5308,6 +5308,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { scene_tree->set_anchors_and_margins_preset(Control::PRESET_WIDE); scene_tree->add_child(p_editor->get_scene_root()); + controls_vb = memnew(VBoxContainer); + controls_vb->set_begin(Point2(5, 5)); + + zoom_hb = memnew(HBoxContainer); + // Bring the zoom percentage closer to the zoom buttons + zoom_hb->add_constant_override("separation", Math::round(-8 * EDSCALE)); + controls_vb->add_child(zoom_hb); + viewport = memnew(CanvasItemEditorViewport(p_editor, this)); viewport_scrollable->add_child(viewport); viewport->set_mouse_filter(MOUSE_FILTER_PASS); @@ -5351,11 +5359,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { v_scroll->connect("value_changed", this, "_update_scroll"); v_scroll->hide(); - zoom_hb = memnew(HBoxContainer); - viewport->add_child(zoom_hb); - zoom_hb->set_begin(Point2(5, 5)); - // Bring the zoom percentage closer to the zoom buttons - zoom_hb->add_constant_override("separation", Math::round(-8 * EDSCALE)); + viewport->add_child(controls_vb); zoom_minus = memnew(ToolButton); zoom_hb->add_child(zoom_minus); @@ -5742,8 +5746,6 @@ void CanvasItemEditorViewport::_on_change_type_closed() { } void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) const { - label->set_position(get_global_position() + Point2(14, 14) * EDSCALE); - label_desc->set_position(label->get_position() + Point2(0, label->get_size().height)); bool add_preview = false; for (int i = 0; i < files.size(); i++) { String path = files[i]; @@ -6165,7 +6167,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte label->add_color_override("font_color_shadow", Color(0, 0, 0, 1)); label->add_constant_override("shadow_as_outline", 1 * EDSCALE); label->hide(); - editor->get_gui_base()->add_child(label); + canvas_item_editor->get_controls_container()->add_child(label); label_desc = memnew(Label); label_desc->set_text(TTR("Drag & drop + Shift : Add node as sibling\nDrag & drop + Alt : Change node type")); @@ -6174,7 +6176,8 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte label_desc->add_constant_override("shadow_as_outline", 1 * EDSCALE); label_desc->add_constant_override("line_spacing", 0); label_desc->hide(); - editor->get_gui_base()->add_child(label_desc); + canvas_item_editor->get_controls_container()->add_child(label_desc); + VS::get_singleton()->canvas_set_disable_scale(true); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 3fdf00d611..3ba66c00f9 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -530,6 +530,7 @@ private: void _button_toggle_anchor_mode(bool p_status); + VBoxContainer *controls_vb; HBoxContainer *zoom_hb; void _zoom_on_position(float p_zoom, Point2 p_position = Point2()); void _update_zoom_label(); @@ -627,6 +628,8 @@ public: Control *get_viewport_control() { return viewport; } + Control *get_controls_container() { return controls_vb; } + void update_viewport(); Tool get_current_tool() { return tool; } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index e0189f8a92..d187e4ff4a 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -965,7 +965,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } if (b->is_pressed()) { - int mod = _get_key_modifier(b); + const int mod = _get_key_modifier(b); if (!orthogonal) { if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) { set_freelook_active(true); @@ -1656,14 +1656,16 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (nav_scheme == NAVIGATION_GODOT) { - int mod = _get_key_modifier(m); + const int mod = _get_key_modifier(m); - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) + if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { nav_mode = NAVIGATION_PAN; - else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) + } else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) { nav_mode = NAVIGATION_ZOOM; - else if (mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) + } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) { + // Always allow Alt as a modifier to better support graphic tablets. nav_mode = NAVIGATION_ORBIT; + } } else if (nav_scheme == NAVIGATION_MAYA) { if (m->get_alt()) @@ -1672,15 +1674,17 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } else if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_3_button_mouse")) { // Handle trackpad (no external mouse) use case - int mod = _get_key_modifier(m); + const int mod = _get_key_modifier(m); if (mod) { - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) + if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { nav_mode = NAVIGATION_PAN; - else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) + } else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) { nav_mode = NAVIGATION_ZOOM; - else if (mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) + } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) { + // Always allow Alt as a modifier to better support graphic tablets. nav_mode = NAVIGATION_ORBIT; + } } } @@ -1727,14 +1731,16 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (nav_scheme == NAVIGATION_GODOT) { - int mod = _get_key_modifier(pan_gesture); + const int mod = _get_key_modifier(pan_gesture); - if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) + if (mod == _get_key_modifier_setting("editors/3d/navigation/pan_modifier")) { nav_mode = NAVIGATION_PAN; - else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) + } else if (mod == _get_key_modifier_setting("editors/3d/navigation/zoom_modifier")) { nav_mode = NAVIGATION_ZOOM; - else if (mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) + } else if (mod == KEY_ALT || mod == _get_key_modifier_setting("editors/3d/navigation/orbit_modifier")) { + // Always allow Alt as a modifier to better support graphic tablets. nav_mode = NAVIGATION_ORBIT; + } } else if (nav_scheme == NAVIGATION_MAYA) { if (pan_gesture->get_alt()) diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 10567557d6..385ba4cfda 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -515,6 +515,7 @@ void TileMapEditor::_update_palette() { sel_tile = selected.get(Math::rand() % selected.size()); } else if (palette->get_item_count() > 0) { palette->select(0); + sel_tile = palette->get_selected_items().get(0); } if (sel_tile != TileMap::INVALID_CELL && ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || (!priority_atlastile && tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE))) { diff --git a/editor/project_export.cpp b/editor/project_export.cpp index adcbddfb04..617ad62d4a 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -1107,6 +1107,7 @@ ProjectExportDialog::ProjectExportDialog() { name->connect("text_changed", this, "_name_changed"); runnable = memnew(CheckButton); runnable->set_text(TTR("Runnable")); + runnable->set_tooltip(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable.")); runnable->connect("pressed", this, "_runnable_pressed"); settings_vb->add_child(runnable); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 9ac775e456..0428aafe7e 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -445,6 +445,7 @@ void ProjectSettingsEditor::_wait_for_key(const Ref<InputEvent> &p_event) { const String str = keycode_get_string(k->get_scancode_with_modifiers()); press_a_key_label->set_text(str); + press_a_key->get_ok()->set_disabled(false); press_a_key->accept_event(); } } @@ -458,6 +459,7 @@ void ProjectSettingsEditor::_add_item(int p_item, Ref<InputEvent> p_exiting_even case INPUT_KEY: { press_a_key_label->set_text(TTR("Press a Key...")); + press_a_key->get_ok()->set_disabled(true); last_wait_for_key = Ref<InputEvent>(); press_a_key->popup_centered(Size2(250, 80) * EDSCALE); press_a_key->grab_focus(); @@ -1958,6 +1960,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { l->set_align(Label::ALIGN_CENTER); l->set_margin(MARGIN_TOP, 20); l->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_BEGIN, 30); + press_a_key->get_ok()->set_disabled(true); press_a_key_label = l; press_a_key->add_child(l); press_a_key->connect("gui_input", this, "_wait_for_key"); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index afbd8832f2..a7f338051a 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -492,7 +492,7 @@ void ScriptEditorDebugger::_video_mem_request() { Size2 ScriptEditorDebugger::get_minimum_size() const { - Size2 ms = Control::get_minimum_size(); + Size2 ms = MarginContainer::get_minimum_size(); ms.y = MAX(ms.y, 250 * EDSCALE); return ms; } @@ -1426,11 +1426,12 @@ void ScriptEditorDebugger::_notification(int p_what) { } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + add_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); + add_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); + tabs->add_style_override("panel", editor->get_gui_base()->get_stylebox("DebuggerPanel", "EditorStyles")); tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles")); tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles")); - tabs->set_margin(MARGIN_LEFT, -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); - tabs->set_margin(MARGIN_RIGHT, EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); copy->set_icon(get_icon("ActionCopy", "EditorIcons")); step->set_icon(get_icon("DebugStep", "EditorIcons")); @@ -2242,6 +2243,9 @@ void ScriptEditorDebugger::_bind_methods() { ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { + add_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); + add_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); + ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream)); ppeer->set_input_buffer_max_size(1024 * 1024 * 8); //8mb should be enough editor = p_editor; @@ -2253,9 +2257,6 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { tabs->add_style_override("tab_fg", editor->get_gui_base()->get_stylebox("DebuggerTabFG", "EditorStyles")); tabs->add_style_override("tab_bg", editor->get_gui_base()->get_stylebox("DebuggerTabBG", "EditorStyles")); - tabs->set_anchors_and_margins_preset(Control::PRESET_WIDE); - tabs->set_margin(MARGIN_LEFT, -editor->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_LEFT)); - tabs->set_margin(MARGIN_RIGHT, editor->get_gui_base()->get_stylebox("BottomPanelDebuggerOverride", "EditorStyles")->get_margin(MARGIN_RIGHT)); add_child(tabs); { //debugger diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index 14b024d066..c885614dab 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -55,9 +55,9 @@ class EditorNetworkProfiler; class ScriptEditorDebuggerInspectedObject; -class ScriptEditorDebugger : public Control { +class ScriptEditorDebugger : public MarginContainer { - GDCLASS(ScriptEditorDebugger, Control); + GDCLASS(ScriptEditorDebugger, MarginContainer); public: enum CameraOverride { diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 16da2771b9..cfd9ec19d2 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -490,7 +490,6 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, if (r_gizmo_handle && !hidden) { Transform t = spatial_node->get_global_transform(); - t.orthonormalize(); if (billboard_handle) { t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1)); } @@ -551,7 +550,6 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, if (selectable_icon_size > 0.0f) { Transform t = spatial_node->get_global_transform(); - t.orthonormalize(); Vector3 camera_position = p_camera->get_camera_transform().origin; if (camera_position.distance_squared_to(t.origin) > 0.01) { t.set_look_at(t.origin, camera_position, Vector3(0, 1, 0)); @@ -861,7 +859,6 @@ void LightSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); Transform gt = light->get_global_transform(); - gt.orthonormalize(); Transform gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); @@ -1106,7 +1103,6 @@ void AudioStreamPlayer3DSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_giz AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); Transform gt = player->get_global_transform(); - gt.orthonormalize(); Transform gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); @@ -1266,7 +1262,6 @@ void CameraSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); Transform gt = camera->get_global_transform(); - gt.orthonormalize(); Transform gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); @@ -3234,7 +3229,6 @@ void CollisionShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, i return; Transform gt = cs->get_global_transform(); - gt.orthonormalize(); Transform gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index e0cf990f83..eace195c33 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -108,6 +108,7 @@ struct ClassAPI { ClassDB::APIType api_type; bool is_singleton; + String singleton_name; bool is_instanciable; // @Unclear bool is_reference; @@ -183,6 +184,7 @@ List<ClassAPI> generate_c_api_classes() { global_constants_api.class_name = L"GlobalConstants"; global_constants_api.api_type = ClassDB::API_CORE; global_constants_api.is_singleton = true; + global_constants_api.singleton_name = L"GlobalConstants"; global_constants_api.is_instanciable = false; const int constants_count = GlobalConstants::get_global_constant_count(); for (int i = 0; i < constants_count; ++i) { @@ -208,6 +210,9 @@ List<ClassAPI> generate_c_api_classes() { name.remove(0); } class_api.is_singleton = Engine::get_singleton()->has_singleton(name); + if (class_api.is_singleton) { + class_api.singleton_name = name; + } } class_api.is_instanciable = !class_api.is_singleton && ClassDB::can_instance(class_name); @@ -421,6 +426,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back("\t\t\"base_class\": \"" + api.super_class_name + "\",\n"); source.push_back(String("\t\t\"api_type\": \"") + (api.api_type == ClassDB::API_CORE ? "core" : (api.api_type == ClassDB::API_EDITOR ? "tools" : "none")) + "\",\n"); source.push_back(String("\t\t\"singleton\": ") + (api.is_singleton ? "true" : "false") + ",\n"); + source.push_back("\t\t\"singleton_name\": \"" + api.singleton_name + "\",\n"); source.push_back(String("\t\t\"instanciable\": ") + (api.is_instanciable ? "true" : "false") + ",\n"); source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n"); // @Unclear diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 1d82735328..280bc37dc0 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -84,14 +84,17 @@ String GDScriptLanguage::_get_processed_template(const String &p_template, const Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { String _template = "extends %BASE%\n" "\n" + "\n" "# Declare member variables here. Examples:\n" "# var a%INT_TYPE% = 2\n" "# var b%STRING_TYPE% = \"text\"\n" "\n" + "\n" "# Called when the node enters the scene tree for the first time.\n" "func _ready()%VOID_RETURN%:\n" "%TS%pass # Replace with function body.\n" "\n" + "\n" "# Called every frame. 'delta' is the elapsed time since the previous frame.\n" "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n" "#%TS%pass\n"; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 74b9440b3a..6ef3ab67ae 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -6466,6 +6466,8 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { DataType true_type = _reduce_node_type(op->arguments[1]); DataType false_type = _reduce_node_type(op->arguments[2]); + // Check arguments[0] errors. + _reduce_node_type(op->arguments[0]); // If types are equal, then the expression is of the same type // If they are compatible, return the broader type diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index c5c8b9adbd..5388061f84 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -44,9 +44,33 @@ def copy_file(src_dir, dst_dir, name): copy(src_path, dst_dir) +def is_desktop(platform): + return platform in ['windows', 'osx', 'x11', 'server', 'uwp', 'haiku'] + + +def is_unix_like(platform): + return platform in ['osx', 'x11', 'server', 'android', 'haiku'] + + +def module_supports_tools_on(platform): + return platform not in ['android', 'javascript'] + + +def find_wasm_src_dir(mono_root): + hint_dirs = [ + os.path.join(mono_root, 'src'), + os.path.join(mono_root, '../src'), + ] + for hint_dir in hint_dirs: + if os.path.isfile(os.path.join(hint_dir, 'driver.c')): + return hint_dir + return '' + + def configure(env, env_mono): bits = env['bits'] is_android = env['platform'] == 'android' + is_javascript = env['platform'] == 'javascript' tools_enabled = env['tools'] mono_static = env['mono_static'] @@ -63,17 +87,21 @@ def configure(env, env_mono): env_mono.Append(CPPDEFINES=['NO_PENDING_EXCEPTIONS']) if is_android and not env['android_arch'] in android_arch_dirs: - raise RuntimeError('This module does not support for the specified \'android_arch\': ' + env['android_arch']) + raise RuntimeError('This module does not support the specified \'android_arch\': ' + env['android_arch']) - if is_android and tools_enabled: - # TODO: Implement this. We have to add the data directory to the apk, concretely the Api and Tools folders. - raise RuntimeError('This module does not currently support building for android with tools enabled') + if tools_enabled and not module_supports_tools_on(env['platform']): + # TODO: + # Android: We have to add the data directory to the apk, concretely the Api and Tools folders. + raise RuntimeError('This module does not currently support building for this platform with tools enabled') if is_android and mono_static: - # When static linking and doing something that requires libmono-native, we get a dlopen error as libmono-native seems to depend on libmonosgen-2.0 - raise RuntimeError('Linking Mono statically is not currently supported on Android') + # Android: When static linking and doing something that requires libmono-native, we get a dlopen error as libmono-native seems to depend on libmonosgen-2.0 + raise RuntimeError('Statically linking Mono is not currently supported on this platform') - if (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')) and not mono_prefix: + if is_javascript: + mono_static = True + + if not mono_prefix and (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')): print("WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead") if env['platform'] == 'windows': @@ -143,7 +171,7 @@ def configure(env, env_mono): mono_lib_path = '' mono_so_name = '' - if not mono_root and is_android: + if not mono_root and (is_android or is_javascript): raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter") if not mono_root and is_apple: @@ -167,7 +195,7 @@ def configure(env, env_mono): mono_lib_path = os.path.join(mono_root, 'lib') - env.Append(LIBPATH=mono_lib_path) + env.Append(LIBPATH=[mono_lib_path]) env_mono.Prepend(CPPPATH=os.path.join(mono_root, 'include', 'mono-2.0')) mono_lib = find_file_in_dir(mono_lib_path, mono_lib_names, prefix='lib', extension='.a') @@ -183,7 +211,30 @@ def configure(env, env_mono): if is_apple: env.Append(LINKFLAGS=['-Wl,-force_load,' + mono_lib_file]) else: + assert is_desktop(env['platform']) or is_android or is_javascript env.Append(LINKFLAGS=['-Wl,-whole-archive', mono_lib_file, '-Wl,-no-whole-archive']) + + if is_javascript: + env.Append(LIBS=['mono-icall-table', 'mono-native', 'mono-ilgen', 'mono-ee-interp']) + + wasm_src_dir = os.path.join(mono_root, 'src') + if not os.path.isdir(wasm_src_dir): + raise RuntimeError('Could not find mono wasm src directory') + + # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours + env_mono.Append(CPPDEFINES=['CORE_BINDINGS']) + + env_mono.add_source_files(env.modules_sources, [ + os.path.join(wasm_src_dir, 'driver.c'), + os.path.join(wasm_src_dir, 'zlib-helper.c'), + os.path.join(wasm_src_dir, 'corebindings.c') + ]) + + env.Append(LINKFLAGS=[ + '--js-library', os.path.join(wasm_src_dir, 'library_mono.js'), + '--js-library', os.path.join(wasm_src_dir, 'binding_support.js'), + '--js-library', os.path.join(wasm_src_dir, 'dotnet_support.js') + ]) else: env.Append(LIBS=[mono_lib]) @@ -191,6 +242,8 @@ def configure(env, env_mono): env.Append(LIBS=['iconv', 'pthread']) elif is_android: pass # Nothing + elif is_javascript: + env.Append(LIBS=['m', 'rt', 'dl', 'pthread']) else: env.Append(LIBS=['m', 'rt', 'dl', 'pthread']) @@ -230,19 +283,22 @@ def configure(env, env_mono): env.Append(LINKFLAGS='-rdynamic') - if not tools_enabled and not is_android: - if not mono_root: - mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip() + if not tools_enabled: + if is_desktop(env['platform']): + if not mono_root: + mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip() - make_template_dir(env, mono_root) - elif not tools_enabled and is_android: - # Compress Android Mono Config - from . import make_android_mono_config - config_file_path = os.path.join(mono_root, 'etc', 'mono', 'config') - make_android_mono_config.generate_compressed_config(config_file_path, 'mono_gd/') + make_template_dir(env, mono_root) + elif is_android: + # Compress Android Mono Config + from . import make_android_mono_config + config_file_path = os.path.join(mono_root, 'etc', 'mono', 'config') + make_android_mono_config.generate_compressed_config(config_file_path, 'mono_gd/') - # Copy the required shared libraries - copy_mono_shared_libs(env, mono_root, None) + # Copy the required shared libraries + copy_mono_shared_libs(env, mono_root, None) + elif is_javascript: + pass # No data directory for this platform if copy_mono_root: if not mono_root: @@ -251,7 +307,7 @@ def configure(env, env_mono): if tools_enabled: copy_mono_root_files(env, mono_root) else: - print("Ignoring option: 'copy_mono_root'. Only available for builds with 'tools' enabled.") + print("Ignoring option: 'copy_mono_root'; only available for builds with 'tools' enabled.") def make_template_dir(env, mono_root): @@ -262,10 +318,9 @@ def make_template_dir(env, mono_root): template_dir_name = '' - if platform in ['windows', 'osx', 'x11', 'android', 'server']: - template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target) - else: - assert False + assert is_desktop(platform) + + template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target) output_dir = Dir('#bin').abspath template_dir = os.path.join(output_dir, template_dir_name) @@ -278,7 +333,7 @@ def make_template_dir(env, mono_root): # Copy etc/mono/ template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono') - copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform']) + copy_mono_etc_dir(mono_root, template_mono_config_dir, platform) # Copy the required shared libraries @@ -377,6 +432,11 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): os.makedirs(target_mono_bin_dir) copy(os.path.join(mono_root, 'bin', 'MonoPosixHelper.dll'), target_mono_bin_dir) + + # For newer versions + btls_dll_path = os.path.join(mono_root, 'bin', 'libmono-btls-shared.dll') + if os.path.isfile(btls_dll_path): + copy(btls_dll_path, target_mono_bin_dir) else: target_mono_lib_dir = get_android_out_dir(env) if platform == 'android' else os.path.join(target_mono_root_dir, 'lib') @@ -386,7 +446,7 @@ def copy_mono_shared_libs(env, mono_root, target_mono_root_dir): if platform == 'osx': # TODO: Make sure nothing is missing copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), target_mono_lib_dir) - elif platform == 'x11' or platform == 'android' or platform == 'server': + elif is_unix_like(platform): lib_file_names = [lib_name + '.so' for lib_name in [ 'libmono-btls-shared', 'libmono-ee-interp', 'libmono-native', 'libMonoPosixHelper', 'libmono-profiler-aot', 'libmono-profiler-coverage', 'libmono-profiler-log', 'libMonoSupportW' diff --git a/modules/mono/build_scripts/patches/fix-mono-android-tkill.diff b/modules/mono/build_scripts/patches/fix-mono-android-tkill.diff deleted file mode 100644 index 05f8dcadcc..0000000000 --- a/modules/mono/build_scripts/patches/fix-mono-android-tkill.diff +++ /dev/null @@ -1,70 +0,0 @@ -diff --git a/libgc/include/private/gcconfig.h b/libgc/include/private/gcconfig.h -index e2bdf13ac3e..f962200ba4e 100644 ---- a/libgc/include/private/gcconfig.h -+++ b/libgc/include/private/gcconfig.h -@@ -2255,6 +2255,14 @@ - # define GETPAGESIZE() getpagesize() - # endif - -+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \ -+ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \ -+ || defined(ARM32) || defined(I386) /* but not x32 */) -+ /* tkill() exists only on arm32/mips(32)/x86. */ -+ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */ -+# define USE_TKILL_ON_ANDROID -+#endif -+ - # if defined(SUNOS5) || defined(DRSNX) || defined(UTS4) - /* OS has SVR4 generic features. Probably others also qualify. */ - # define SVR4 -diff --git a/libgc/pthread_stop_world.c b/libgc/pthread_stop_world.c -index f93ce26b562..4a49a6d578c 100644 ---- a/libgc/pthread_stop_world.c -+++ b/libgc/pthread_stop_world.c -@@ -336,7 +336,7 @@ void GC_push_all_stacks() - pthread_t GC_stopping_thread; - int GC_stopping_pid; - --#ifdef HOST_ANDROID -+#ifdef USE_TKILL_ON_ANDROID - static - int android_thread_kill(pid_t tid, int sig) - { -diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c -index ad9b8823f8f..3542b32b540 100644 ---- a/mono/metadata/threads.c -+++ b/mono/metadata/threads.c -@@ -77,8 +77,12 @@ mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle); - #include <zircon/syscalls.h> - #endif - --#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64) --#define USE_TKILL_ON_ANDROID 1 -+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \ -+ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \ -+ || defined(ARM32) || defined(I386) /* but not x32 */) -+ /* tkill() exists only on arm32/mips(32)/x86. */ -+ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */ -+# define USE_TKILL_ON_ANDROID - #endif - - #ifdef HOST_ANDROID -diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c -index 3e4bf93de5f..79c9f731fe7 100644 ---- a/mono/utils/mono-threads-posix.c -+++ b/mono/utils/mono-threads-posix.c -@@ -31,8 +31,12 @@ - - #include <errno.h> - --#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64) --#define USE_TKILL_ON_ANDROID 1 -+#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \ -+ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \ -+ || defined(ARM32) || defined(I386) /* but not x32 */) -+ /* tkill() exists only on arm32/mips(32)/x86. */ -+ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */ -+# define USE_TKILL_ON_ANDROID - #endif - - #ifdef USE_TKILL_ON_ANDROID diff --git a/modules/mono/config.py b/modules/mono/config.py index 9adf4ee6e5..70cb464c7a 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -1,10 +1,11 @@ def can_build(env, platform): - if platform in ['javascript']: - return False # Not yet supported return True def configure(env): + if env['platform'] not in ['windows', 'osx', 'x11', 'server', 'android', 'haiku', 'javascript']: + raise RuntimeError('This module does not currently support building for this platform') + env.use_ptrcall = True env.add_module_version_string('mono') @@ -18,6 +19,13 @@ def configure(env): envvars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False)) envvars.Update(env) + if env['platform'] == 'javascript': + # Mono wasm already has zlib builtin, so we need this workaround to avoid symbol collisions + print('Compiling with Mono wasm disables \'builtin_zlib\'') + env['builtin_zlib'] = False + thirdparty_zlib_dir = "#thirdparty/zlib/" + env.Prepend(CPPPATH=[thirdparty_zlib_dir]) + def get_doc_classes(): return [ diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 83be10dee3..34dcde40f4 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -50,8 +50,10 @@ #include "editor/editor_internal_calls.h" #include "godotsharp_dirs.h" +#include "mono_gd/gd_mono_cache.h" #include "mono_gd/gd_mono_class.h" #include "mono_gd/gd_mono_marshal.h" +#include "mono_gd/gd_mono_utils.h" #include "signal_awaiter_utils.h" #include "utils/macros.h" #include "utils/mutex_utils.h" @@ -130,8 +132,6 @@ void CSharpLanguage::init() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(&_editor_init_callback); - - GLOBAL_DEF("mono/export/include_scripts_content", false); #endif } @@ -545,7 +545,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() #ifdef DEBUG_ENABLED _TLS_RECURSION_GUARD_V_(Vector<StackInfo>()); - if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoUtils::mono_cache.corlib_cache_updated) + if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated) return Vector<StackInfo>(); MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr()); @@ -571,7 +571,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec MonoException *exc = NULL; - MonoArray *frames = invoke_method_thunk(CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames), p_stack_trace, &exc); + MonoArray *frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames).invoke(p_stack_trace, &exc); if (exc) { GDMonoUtils::debug_print_unhandled_exception(exc); @@ -583,8 +583,6 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec if (frame_count <= 0) return Vector<StackInfo>(); - GDMonoUtils::DebugUtils_StackFrameInfo get_sf_info = CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo); - Vector<StackInfo> si; si.resize(frame_count); @@ -595,7 +593,7 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec MonoString *file_name; int file_line_num; MonoString *method_decl; - invoke_method_thunk(get_sf_info, frame, &file_name, &file_line_num, &method_decl, &exc); + CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo).invoke(frame, &file_name, &file_line_num, &method_decl, &exc); if (exc) { GDMonoUtils::debug_print_unhandled_exception(exc); @@ -618,14 +616,14 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObjec void CSharpLanguage::frame() { if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != NULL) { - const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoUtils::mono_cache.task_scheduler_handle; + const Ref<MonoGCHandle> &task_scheduler_handle = GDMonoCache::cached_data.task_scheduler_handle; if (task_scheduler_handle.is_valid()) { MonoObject *task_scheduler = task_scheduler_handle->get_target(); if (task_scheduler) { MonoException *exc = NULL; - invoke_method_thunk(CACHED_METHOD_THUNK(GodotTaskScheduler, Activate), task_scheduler, &exc); + CACHED_METHOD_THUNK(GodotTaskScheduler, Activate).invoke(task_scheduler, &exc); if (exc) { GDMonoUtils::debug_unhandled_exception(exc); @@ -1079,7 +1077,7 @@ bool CSharpLanguage::overrides_external_editor() { void CSharpLanguage::thread_enter() { #if 0 - if (mono->is_runtime_initialized()) { + if (gdmono->is_runtime_initialized()) { GDMonoUtils::attach_current_thread(); } #endif @@ -1088,7 +1086,7 @@ void CSharpLanguage::thread_enter() { void CSharpLanguage::thread_exit() { #if 0 - if (mono->is_runtime_initialized()) { + if (gdmono->is_runtime_initialized()) { GDMonoUtils::detach_current_thread(); } #endif diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs index 9a2b2e3a26..da90c960e5 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs @@ -44,7 +44,7 @@ namespace GodotTools.Build { get { - if (OS.IsWindows()) + if (OS.IsWindows) { return (BuildManager.BuildTool) EditorSettings.GetSetting("mono/builds/build_tool") == BuildManager.BuildTool.MsBuildMono; diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs index eb2c2dd77c..ad8a6516ab 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs @@ -21,7 +21,7 @@ namespace GodotTools.Build var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings(); var buildTool = (BuildManager.BuildTool) editorSettings.GetSetting("mono/builds/build_tool"); - if (OS.IsWindows()) + if (OS.IsWindows) { switch (buildTool) { @@ -59,7 +59,7 @@ namespace GodotTools.Build } } - if (OS.IsUnix()) + if (OS.IsUnixLike()) { if (buildTool == BuildManager.BuildTool.MsBuildMono) { @@ -91,7 +91,7 @@ namespace GodotTools.Build { var result = new List<string>(); - if (OS.IsOSX()) + if (OS.IsOSX) { result.Add("/Library/Frameworks/Mono.framework/Versions/Current/bin/"); result.Add("/usr/local/var/homebrew/linked/mono/bin/"); @@ -128,7 +128,7 @@ namespace GodotTools.Build private static string FindMsBuildToolsPathOnWindows() { - if (!OS.IsWindows()) + if (!OS.IsWindows) throw new PlatformNotSupportedException(); // Try to find 15.0 with vswhere diff --git a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs index ab37d89955..217bf5c144 100644 --- a/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/BuildManager.cs @@ -246,7 +246,7 @@ namespace GodotTools { // Build tool settings - EditorDef("mono/builds/build_tool", OS.IsWindows() ? BuildTool.MsBuildVs : BuildTool.MsBuildMono); + EditorDef("mono/builds/build_tool", OS.IsWindows ? BuildTool.MsBuildVs : BuildTool.MsBuildMono); var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings(); @@ -255,7 +255,7 @@ namespace GodotTools ["type"] = Godot.Variant.Type.Int, ["name"] = "mono/builds/build_tool", ["hint"] = Godot.PropertyHint.Enum, - ["hint_string"] = OS.IsWindows() ? + ["hint_string"] = OS.IsWindows ? $"{PropNameMsbuildMono},{PropNameMsbuildVs}" : $"{PropNameMsbuildMono}" }); diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs new file mode 100644 index 0000000000..f65d2a39f4 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -0,0 +1,615 @@ +using Godot; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using GodotTools.Core; +using GodotTools.Internals; +using static GodotTools.Internals.Globals; +using Directory = GodotTools.Utils.Directory; +using File = GodotTools.Utils.File; +using OS = GodotTools.Utils.OS; +using Path = System.IO.Path; + +namespace GodotTools.Export +{ + public class ExportPlugin : EditorExportPlugin + { + public void RegisterExportSettings() + { + // TODO: These would be better as export preset options, but that doesn't seem to be supported yet + + GlobalDef("mono/export/include_scripts_content", false); + + GlobalDef("mono/export/aot/enabled", false); + GlobalDef("mono/export/aot/full_aot", false); + + // --aot or --aot=opt1,opt2 (use 'mono --aot=help AuxAssembly.dll' to list AOT options) + GlobalDef("mono/export/aot/extra_aot_options", new string[] { }); + // --optimize/-O=opt1,opt2 (use 'mono --list-opt'' to list optimize options) + GlobalDef("mono/export/aot/extra_optimizer_options", new string[] { }); + + GlobalDef("mono/export/aot/android_toolchain_path", ""); + } + + private string maybeLastExportError; + + private void AddFile(string srcPath, string dstPath, bool remap = false) + { + AddFile(dstPath, File.ReadAllBytes(srcPath), remap); + } + + public override void _ExportFile(string path, string type, string[] features) + { + base._ExportFile(path, type, features); + + if (type != Internal.CSharpLanguageType) + return; + + if (Path.GetExtension(path) != $".{Internal.CSharpLanguageExtension}") + throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path)); + + // TODO What if the source file is not part of the game's C# project + + bool includeScriptsContent = (bool) ProjectSettings.GetSetting("mono/export/include_scripts_content"); + + if (!includeScriptsContent) + { + // We don't want to include the source code on exported games. + + // Sadly, Godot prints errors when adding an empty file (nothing goes wrong, it's just noise). + // Because of this, we add a file which contains a line break. + AddFile(path, System.Text.Encoding.UTF8.GetBytes("\n"), remap: false); + Skip(); + } + } + + public override void _ExportBegin(string[] features, bool isDebug, string path, int flags) + { + base._ExportBegin(features, isDebug, path, flags); + + try + { + _ExportBeginImpl(features, isDebug, path, flags); + } + catch (Exception e) + { + maybeLastExportError = e.Message; + GD.PushError($"Failed to export project: {e.Message}"); + Console.Error.WriteLine(e); + // TODO: Do something on error once _ExportBegin supports failing. + } + } + + private void _ExportBeginImpl(string[] features, bool isDebug, string path, int flags) + { + if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) + return; + + string platform = DeterminePlatformFromFeatures(features); + + if (platform == null) + throw new NotSupportedException("Target platform not supported"); + + string outputDir = new FileInfo(path).Directory?.FullName ?? + throw new FileNotFoundException("Base directory not found"); + + string buildConfig = isDebug ? "Debug" : "Release"; + + string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}"); + CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath); + + AddFile(scriptsMetadataPath, scriptsMetadataPath); + + // Turn export features into defines + var godotDefines = features; + + if (!BuildManager.BuildProjectBlocking(buildConfig, godotDefines)) + throw new Exception("Failed to build project"); + + // Add dependency assemblies + + var dependencies = new Godot.Collections.Dictionary<string, string>(); + + var projectDllName = (string) ProjectSettings.GetSetting("application/config/name"); + if (projectDllName.Empty()) + { + projectDllName = "UnnamedProject"; + } + + string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig); + string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll"); + + dependencies[projectDllName] = projectDllSrcPath; + + { + string platformBclDir = DeterminePlatformBclDir(platform); + + internal_GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, platformBclDir, dependencies); + } + + string apiConfig = isDebug ? "Debug" : "Release"; + string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig); + + foreach (var dependency in dependencies) + { + string dependSrcPath = dependency.Value; + string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile()); + AddFile(dependSrcPath, dependDstPath); + } + + // Mono specific export template extras (data dir) + string outputDataDir = null; + + if (PlatformHasTemplateDir(platform)) + outputDataDir = ExportDataDirectory(features, platform, isDebug, outputDir); + + // AOT + + if ((bool) ProjectSettings.GetSetting("mono/export/aot/enabled")) + { + AotCompileDependencies(features, platform, isDebug, outputDir, outputDataDir, dependencies); + } + } + + public override void _ExportEnd() + { + base._ExportEnd(); + + string aotTempDir = Path.Combine(Path.GetTempPath(), $"godot-aot-{Process.GetCurrentProcess().Id}"); + + if (Directory.Exists(aotTempDir)) + Directory.Delete(aotTempDir, recursive: true); + + // TODO: Just a workaround until the export plugins can be made to abort with errors + if (string.IsNullOrEmpty(maybeLastExportError)) // Check empty as well, because it's set to empty after hot-reloading + { + string lastExportError = maybeLastExportError; + maybeLastExportError = null; + + GodotSharpEditor.Instance.ShowErrorDialog(lastExportError, "C# export failed"); + } + } + + private static string ExportDataDirectory(string[] features, string platform, bool isDebug, string outputDir) + { + string target = isDebug ? "release_debug" : "release"; + + // NOTE: Bits is ok for now as all platforms with a data directory have it, but that may change in the future. + string bits = features.Contains("64") ? "64" : "32"; + + string TemplateDirName() => $"data.mono.{platform}.{bits}.{target}"; + + string templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName()); + + if (!Directory.Exists(templateDirPath)) + { + templateDirPath = null; + + if (isDebug) + { + target = "debug"; // Support both 'release_debug' and 'debug' for the template data directory name + templateDirPath = Path.Combine(Internal.FullTemplatesDir, TemplateDirName()); + + if (!Directory.Exists(templateDirPath)) + templateDirPath = null; + } + } + + if (templateDirPath == null) + throw new FileNotFoundException("Data template directory not found"); + + string outputDataDir = Path.Combine(outputDir, DataDirName); + + if (Directory.Exists(outputDataDir)) + Directory.Delete(outputDataDir, recursive: true); // Clean first + + Directory.CreateDirectory(outputDataDir); + + foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories)) + { + Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1))); + } + + foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories)) + { + File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1))); + } + + return outputDataDir; + } + + private void AotCompileDependencies(string[] features, string platform, bool isDebug, string outputDir, string outputDataDir, IDictionary<string, string> dependencies) + { + // TODO: WASM + + string bclDir = DeterminePlatformBclDir(platform) ?? typeof(object).Assembly.Location.GetBaseDir(); + + string aotTempDir = Path.Combine(Path.GetTempPath(), $"godot-aot-{Process.GetCurrentProcess().Id}"); + + if (!Directory.Exists(aotTempDir)) + Directory.CreateDirectory(aotTempDir); + + var assemblies = new Dictionary<string, string>(); + + foreach (var dependency in dependencies) + { + string assemblyName = dependency.Key; + string assemblyPath = dependency.Value; + + string assemblyPathInBcl = Path.Combine(bclDir, assemblyName + ".dll"); + + if (File.Exists(assemblyPathInBcl)) + { + // Don't create teporaries for assemblies from the BCL + assemblies.Add(assemblyName, assemblyPathInBcl); + } + else + { + string tempAssemblyPath = Path.Combine(aotTempDir, assemblyName + ".dll"); + File.Copy(assemblyPath, tempAssemblyPath); + assemblies.Add(assemblyName, tempAssemblyPath); + } + } + + foreach (var assembly in assemblies) + { + string assemblyName = assembly.Key; + string assemblyPath = assembly.Value; + + string sharedLibExtension = platform == OS.Platforms.Windows ? ".dll" : + platform == OS.Platforms.OSX ? ".dylib" : + platform == OS.Platforms.HTML5 ? ".wasm" : + ".so"; + + string outputFileName = assemblyName + ".dll" + sharedLibExtension; + + if (platform == OS.Platforms.Android) + { + // Not sure if the 'lib' prefix is an Android thing or just Godot being picky, + // but we use '-aot-' as well just in case to avoid conflicts with other libs. + outputFileName = "lib-aot-" + outputFileName; + } + + string outputFilePath = null; + string tempOutputFilePath; + + switch (platform) + { + case OS.Platforms.OSX: + tempOutputFilePath = Path.Combine(aotTempDir, outputFileName); + break; + case OS.Platforms.Android: + tempOutputFilePath = Path.Combine(aotTempDir, "%%ANDROID_ABI%%", outputFileName); + break; + case OS.Platforms.HTML5: + tempOutputFilePath = Path.Combine(aotTempDir, outputFileName); + outputFilePath = Path.Combine(outputDir, outputFileName); + break; + default: + tempOutputFilePath = Path.Combine(aotTempDir, outputFileName); + outputFilePath = Path.Combine(outputDataDir, "Mono", platform == OS.Platforms.Windows ? "bin" : "lib", outputFileName); + break; + } + + var data = new Dictionary<string, string>(); + var enabledAndroidAbis = platform == OS.Platforms.Android ? GetEnabledAndroidAbis(features).ToArray() : null; + + if (platform == OS.Platforms.Android) + { + Debug.Assert(enabledAndroidAbis != null); + + foreach (var abi in enabledAndroidAbis) + { + data["abi"] = abi; + var outputFilePathForThisAbi = tempOutputFilePath.Replace("%%ANDROID_ABI%%", abi); + + AotCompileAssembly(platform, isDebug, data, assemblyPath, outputFilePathForThisAbi); + + AddSharedObject(outputFilePathForThisAbi, tags: new[] {abi}); + } + } + else + { + string bits = features.Contains("64") ? "64" : features.Contains("64") ? "32" : null; + + if (bits != null) + data["bits"] = bits; + + AotCompileAssembly(platform, isDebug, data, assemblyPath, tempOutputFilePath); + + if (platform == OS.Platforms.OSX) + { + AddSharedObject(tempOutputFilePath, tags: null); + } + else + { + Debug.Assert(outputFilePath != null); + File.Copy(tempOutputFilePath, outputFilePath); + } + } + } + } + + private static void AotCompileAssembly(string platform, bool isDebug, Dictionary<string, string> data, string assemblyPath, string outputFilePath) + { + // Make sure the output directory exists + Directory.CreateDirectory(outputFilePath.GetBaseDir()); + + string exeExt = OS.IsWindows ? ".exe" : string.Empty; + + string monoCrossDirName = DetermineMonoCrossDirName(platform, data); + string monoCrossRoot = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "aot-compilers", monoCrossDirName); + string monoCrossBin = Path.Combine(monoCrossRoot, "bin"); + + string toolPrefix = DetermineToolPrefix(monoCrossBin); + string monoExeName = System.IO.File.Exists(Path.Combine(monoCrossBin, $"{toolPrefix}mono{exeExt}")) ? "mono" : "mono-sgen"; + + string compilerCommand = Path.Combine(monoCrossBin, $"{toolPrefix}{monoExeName}{exeExt}"); + + bool fullAot = (bool) ProjectSettings.GetSetting("mono/export/aot/full_aot"); + + string EscapeOption(string option) => option.Contains(',') ? $"\"{option}\"" : option; + string OptionsToString(IEnumerable<string> options) => string.Join(",", options.Select(EscapeOption)); + + var aotOptions = new List<string>(); + var optimizerOptions = new List<string>(); + + if (fullAot) + aotOptions.Add("full"); + + aotOptions.Add(isDebug ? "soft-debug" : "nodebug"); + + if (platform == OS.Platforms.Android) + { + string abi = data["abi"]; + + string androidToolchain = (string) ProjectSettings.GetSetting("mono/export/aot/android_toolchain_path"); + + if (string.IsNullOrEmpty(androidToolchain)) + { + androidToolchain = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "android-toolchains", $"{abi}"); // TODO: $"{abi}-{apiLevel}{(clang?"clang":"")}" + + if (!Directory.Exists(androidToolchain)) + throw new FileNotFoundException("Missing android toolchain. Specify one in the AOT export settings."); + } + else if (!Directory.Exists(androidToolchain)) + { + throw new FileNotFoundException("Android toolchain not found: " + androidToolchain); + } + + var androidToolPrefixes = new Dictionary<string, string> + { + ["armeabi-v7a"] = "arm-linux-androideabi-", + ["arm64-v8a"] = "aarch64-linux-android-", + ["x86"] = "i686-linux-android-", + ["x86_64"] = "x86_64-linux-android-" + }; + + aotOptions.Add("tool-prefix=" + Path.Combine(androidToolchain, "bin", androidToolPrefixes[abi])); + + string triple = GetAndroidTriple(abi); + aotOptions.Add ($"mtriple={triple}"); + } + + aotOptions.Add($"outfile={outputFilePath}"); + + var extraAotOptions = (string[]) ProjectSettings.GetSetting("mono/export/aot/extra_aot_options"); + var extraOptimizerOptions = (string[]) ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options"); + + if (extraAotOptions.Length > 0) + aotOptions.AddRange(extraAotOptions); + + if (extraOptimizerOptions.Length > 0) + optimizerOptions.AddRange(extraOptimizerOptions); + + var compilerArgs = new List<string>(); + + if (isDebug) + compilerArgs.Add("--debug"); // Required for --aot=soft-debug + + compilerArgs.Add(aotOptions.Count > 0 ? $"--aot={OptionsToString(aotOptions)}" : "--aot"); + + if (optimizerOptions.Count > 0) + compilerArgs.Add($"-O={OptionsToString(optimizerOptions)}"); + + compilerArgs.Add(ProjectSettings.GlobalizePath(assemblyPath)); + + // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead + string CmdLineArgsToString(IEnumerable<string> args) + { + // Not perfect, but as long as we are careful... + return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg)); + } + + using (var process = new Process()) + { + process.StartInfo = new ProcessStartInfo(compilerCommand, CmdLineArgsToString(compilerArgs)) + { + UseShellExecute = false + }; + + string platformBclDir = DeterminePlatformBclDir(platform); + process.StartInfo.EnvironmentVariables.Add("MONO_PATH", string.IsNullOrEmpty(platformBclDir) ? + typeof(object).Assembly.Location.GetBaseDir() : + platformBclDir); + + Console.WriteLine($"Running: \"{process.StartInfo.FileName}\" {process.StartInfo.Arguments}"); + + if (!process.Start()) + throw new Exception("Failed to start process for Mono AOT compiler"); + + process.WaitForExit(); + + if (process.ExitCode != 0) + throw new Exception($"Mono AOT compiler exited with error code: {process.ExitCode}"); + + if (!System.IO.File.Exists(outputFilePath)) + throw new Exception("Mono AOT compiler finished successfully but the output file is missing"); + } + } + + private static string DetermineMonoCrossDirName(string platform, IReadOnlyDictionary<string, string> data) + { + switch (platform) + { + case OS.Platforms.Windows: + case OS.Platforms.UWP: + { + string arch = data["bits"] == "64" ? "x86_64" : "i686"; + return $"windows-{arch}"; + } + case OS.Platforms.OSX: + { + string arch = "x86_64"; + return $"{platform}-{arch}"; + } + case OS.Platforms.X11: + case OS.Platforms.Server: + { + string arch = data["bits"] == "64" ? "x86_64" : "i686"; + return $"linux-{arch}"; + } + case OS.Platforms.Haiku: + { + string arch = data["bits"] == "64" ? "x86_64" : "i686"; + return $"{platform}-{arch}"; + } + case OS.Platforms.Android: + { + string abi = data["abi"]; + return $"{platform}-{abi}"; + } + case OS.Platforms.HTML5: + return "wasm-wasm32"; + default: + throw new NotSupportedException(); + } + } + + private static string DetermineToolPrefix(string monoCrossBin) + { + string exeExt = OS.IsWindows ? ".exe" : string.Empty; + + if (System.IO.File.Exists(Path.Combine(monoCrossBin, $"mono{exeExt}"))) + return string.Empty; + + if (System.IO.File.Exists(Path.Combine(monoCrossBin, $"mono-sgen{exeExt}" + exeExt))) + return string.Empty; + + var files = new DirectoryInfo(monoCrossBin).GetFiles($"*mono{exeExt}" + exeExt, SearchOption.TopDirectoryOnly); + if (files.Length > 0) + { + string fileName = files[0].Name; + return fileName.Substring(0, fileName.Length - $"mono{exeExt}".Length); + } + + files = new DirectoryInfo(monoCrossBin).GetFiles($"*mono-sgen{exeExt}" + exeExt, SearchOption.TopDirectoryOnly); + if (files.Length > 0) + { + string fileName = files[0].Name; + return fileName.Substring(0, fileName.Length - $"mono-sgen{exeExt}".Length); + } + + throw new FileNotFoundException($"Cannot find the mono runtime executable in {monoCrossBin}"); + } + + private static IEnumerable<string> GetEnabledAndroidAbis(string[] features) + { + var androidAbis = new[] + { + "armeabi-v7a", + "arm64-v8a", + "x86", + "x86_64" + }; + + return androidAbis.Where(features.Contains); + } + + private static string GetAndroidTriple(string abi) + { + var abiArchs = new Dictionary<string, string> + { + ["armeabi-v7a"] = "armv7", + ["arm64-v8a"] = "aarch64-v8a", + ["x86"] = "i686", + ["x86_64"] = "x86_64" + }; + + string arch = abiArchs[abi]; + + return $"{arch}-linux-android"; + } + + private static bool PlatformHasTemplateDir(string platform) + { + // OSX export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest. + return !new[] {OS.Platforms.OSX, OS.Platforms.Android, OS.Platforms.HTML5}.Contains(platform); + } + + private static string DeterminePlatformFromFeatures(IEnumerable<string> features) + { + foreach (var feature in features) + { + if (OS.PlatformNameMap.TryGetValue(feature, out string platform)) + return platform; + } + + return null; + } + + private static string DeterminePlatformBclDir(string platform) + { + string templatesDir = Internal.FullTemplatesDir; + string platformBclDir = Path.Combine(templatesDir, "bcl", platform); + + if (!File.Exists(Path.Combine(platformBclDir, "mscorlib.dll"))) + { + string profile = DeterminePlatformBclProfile(platform); + platformBclDir = Path.Combine(templatesDir, "bcl", profile); + + if (!File.Exists(Path.Combine(platformBclDir, "mscorlib.dll"))) + platformBclDir = null; // Use the one we're running on + } + + return platformBclDir; + } + + private static string DeterminePlatformBclProfile(string platform) + { + switch (platform) + { + case OS.Platforms.Windows: + case OS.Platforms.UWP: + case OS.Platforms.OSX: + case OS.Platforms.X11: + case OS.Platforms.Server: + case OS.Platforms.Haiku: + return "net_4_x"; + case OS.Platforms.Android: + return "monodroid"; + case OS.Platforms.HTML5: + return "wasm"; + default: + throw new NotSupportedException(); + } + } + + private static string DataDirName + { + get + { + var appName = (string) ProjectSettings.GetSetting("application/config/name"); + string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false); + return $"data_{appNameSafe}"; + } + } + + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void internal_GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath, + string buildConfig, string customBclDir, Godot.Collections.Dictionary<string, string> dependencies); + } +} diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 12edd651df..2a5d3de126 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -1,4 +1,5 @@ using Godot; +using GodotTools.Export; using GodotTools.Utils; using System; using System.Collections.Generic; @@ -225,7 +226,7 @@ namespace GodotTools bool osxAppBundleInstalled = false; - if (OS.IsOSX()) + if (OS.IsOSX) { // The package path is '/Applications/Visual Studio Code.app' const string vscodeBundleId = "com.microsoft.VSCode"; @@ -265,7 +266,7 @@ namespace GodotTools string command; - if (OS.IsOSX()) + if (OS.IsOSX) { if (!osxAppBundleInstalled && _vsCodePath.Empty()) { @@ -415,18 +416,18 @@ namespace GodotTools string settingsHintStr = "Disabled"; - if (OS.IsWindows()) + if (OS.IsWindows) { settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" + $",Visual Studio Code:{(int) ExternalEditorId.VsCode}"; } - else if (OS.IsOSX()) + else if (OS.IsOSX) { settingsHintStr += $",Visual Studio:{(int) ExternalEditorId.VisualStudioForMac}" + $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" + $",Visual Studio Code:{(int) ExternalEditorId.VsCode}"; } - else if (OS.IsUnix()) + else if (OS.IsUnixLike()) { settingsHintStr += $",MonoDevelop:{(int) ExternalEditorId.MonoDevelop}" + $",Visual Studio Code:{(int) ExternalEditorId.VsCode}"; @@ -441,8 +442,9 @@ namespace GodotTools }); // Export plugin - var exportPlugin = new GodotSharpExport(); + var exportPlugin = new ExportPlugin(); AddExportPlugin(exportPlugin); + exportPlugin.RegisterExportSettings(); exportPluginWeak = WeakRef(exportPlugin); BuildManager.Initialize(); @@ -461,7 +463,7 @@ namespace GodotTools // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid // will be freed after EditorSettings already was, and its device polling thread // will try to access the EditorSettings singleton, resulting in null dereferencing. - (exportPluginWeak.GetRef() as GodotSharpExport)?.Dispose(); + (exportPluginWeak.GetRef() as ExportPlugin)?.Dispose(); exportPluginWeak.Dispose(); } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs deleted file mode 100644 index 4f93ef8530..0000000000 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpExport.cs +++ /dev/null @@ -1,197 +0,0 @@ -using Godot; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using GodotTools.Core; -using GodotTools.Internals; -using Directory = GodotTools.Utils.Directory; -using File = GodotTools.Utils.File; -using Path = System.IO.Path; - -namespace GodotTools -{ - public class GodotSharpExport : EditorExportPlugin - { - private void AddFile(string srcPath, string dstPath, bool remap = false) - { - AddFile(dstPath.Replace("\\", "/"), File.ReadAllBytes(srcPath), remap); - } - - public override void _ExportFile(string path, string type, string[] features) - { - base._ExportFile(path, type, features); - - if (type != Internal.CSharpLanguageType) - return; - - if (Path.GetExtension(path) != $".{Internal.CSharpLanguageExtension}") - throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path)); - - // TODO What if the source file is not part of the game's C# project - - bool includeScriptsContent = (bool) ProjectSettings.GetSetting("mono/export/include_scripts_content"); - - if (!includeScriptsContent) - { - // We don't want to include the source code on exported games - AddFile(path, new byte[] { }, remap: false); - Skip(); - } - } - - public override void _ExportBegin(string[] features, bool isDebug, string path, int flags) - { - base._ExportBegin(features, isDebug, path, flags); - - try - { - _ExportBeginImpl(features, isDebug, path, flags); - } - catch (Exception e) - { - GD.PushError($"Failed to export project. Exception message: {e.Message}"); - Console.Error.WriteLine(e); - } - } - - public void _ExportBeginImpl(string[] features, bool isDebug, string path, int flags) - { - // TODO Right now there is no way to stop the export process with an error - - if (File.Exists(GodotSharpDirs.ProjectSlnPath)) - { - string buildConfig = isDebug ? "Debug" : "Release"; - - string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}"); - CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath); - - AddFile(scriptsMetadataPath, scriptsMetadataPath); - - // Turn export features into defines - var godotDefines = features; - - if (!BuildManager.BuildProjectBlocking(buildConfig, godotDefines)) - { - GD.PushError("Failed to build project"); - return; - } - - // Add dependency assemblies - - var dependencies = new Godot.Collections.Dictionary<string, string>(); - - var projectDllName = (string) ProjectSettings.GetSetting("application/config/name"); - if (projectDllName.Empty()) - { - projectDllName = "UnnamedProject"; - } - - string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig); - string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll"); - - dependencies[projectDllName] = projectDllSrcPath; - - { - string templatesDir = Internal.FullTemplatesDir; - string androidBclDir = Path.Combine(templatesDir, "android-bcl"); - - string customLibDir = features.Contains("Android") && Directory.Exists(androidBclDir) ? androidBclDir : string.Empty; - - GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customLibDir, dependencies); - } - - string apiConfig = isDebug ? "Debug" : "Release"; - string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig); - - foreach (var dependency in dependencies) - { - string dependSrcPath = dependency.Value; - string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile()); - AddFile(dependSrcPath, dependDstPath); - } - } - - // Mono specific export template extras (data dir) - ExportDataDirectory(features, isDebug, path); - } - - private static void ExportDataDirectory(IEnumerable<string> features, bool debug, string path) - { - var featureSet = new HashSet<string>(features); - - if (!PlatformHasTemplateDir(featureSet)) - return; - - string templateDirName = "data.mono"; - - if (featureSet.Contains("Windows")) - { - templateDirName += ".windows"; - templateDirName += featureSet.Contains("64") ? ".64" : ".32"; - } - else if (featureSet.Contains("X11")) - { - templateDirName += ".x11"; - templateDirName += featureSet.Contains("64") ? ".64" : ".32"; - } - else - { - throw new NotSupportedException("Target platform not supported"); - } - - templateDirName += debug ? ".release_debug" : ".release"; - - string templateDirPath = Path.Combine(Internal.FullTemplatesDir, templateDirName); - - if (!Directory.Exists(templateDirPath)) - throw new FileNotFoundException("Data template directory not found"); - - string outputDir = new FileInfo(path).Directory?.FullName ?? - throw new FileNotFoundException("Base directory not found"); - - string outputDataDir = Path.Combine(outputDir, DataDirName); - - if (Directory.Exists(outputDataDir)) - Directory.Delete(outputDataDir, recursive: true); // Clean first - - Directory.CreateDirectory(outputDataDir); - - foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories)) - { - Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1))); - } - - foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories)) - { - File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1))); - } - } - - private static bool PlatformHasTemplateDir(IEnumerable<string> featureSet) - { - // OSX export templates are contained in a zip, so we place - // our custom template inside it and let Godot do the rest. - return !featureSet.Any(f => new[] {"OSX", "Android"}.Contains(f)); - } - - private static string DataDirName - { - get - { - var appName = (string) ProjectSettings.GetSetting("application/config/name"); - string appNameSafe = appName.ToSafeDirName(allowDirSeparator: false); - return $"data_{appNameSafe}"; - } - } - - private static void GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath, - string buildConfig, string customLibDir, Godot.Collections.Dictionary<string, string> dependencies) => - internal_GetExportedAssemblyDependencies(projectDllName, projectDllSrcPath, buildConfig, customLibDir, dependencies); - - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void internal_GetExportedAssemblyDependencies(string projectDllName, string projectDllSrcPath, - string buildConfig, string customLibDir, Godot.Collections.Dictionary<string, string> dependencies); - } -} diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index 3c57900873..d0c78d095b 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -40,6 +40,7 @@ </ItemGroup> <ItemGroup> <Compile Include="Build\MsBuildFinder.cs" /> + <Compile Include="Export\ExportPlugin.cs" /> <Compile Include="ExternalEditorId.cs" /> <Compile Include="Ides\GodotIdeManager.cs" /> <Compile Include="Ides\GodotIdeServer.cs" /> @@ -63,7 +64,6 @@ <Compile Include="BuildInfo.cs" /> <Compile Include="BuildTab.cs" /> <Compile Include="BottomPanel.cs" /> - <Compile Include="GodotSharpExport.cs" /> <Compile Include="CsProjOperations.cs" /> <Compile Include="Utils\CollectionExtensions.cs" /> </ItemGroup> diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs index 01aa0d0ab1..f94d6f998c 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs @@ -79,7 +79,7 @@ namespace GodotTools.Ides { MonoDevelop.Instance GetMonoDevelopInstance(string solutionPath) { - if (Utils.OS.IsOSX() && editor == ExternalEditorId.VisualStudioForMac) + if (Utils.OS.IsOSX && editor == ExternalEditorId.VisualStudioForMac) { vsForMacInstance = vsForMacInstance ?? new MonoDevelop.Instance(solutionPath, MonoDevelop.EditorId.VisualStudioForMac); diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs index 1fdccf5bbd..6026c109ad 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MonoDevelop/Instance.cs @@ -24,7 +24,7 @@ namespace GodotTools.Ides.MonoDevelop string command; - if (OS.IsOSX()) + if (OS.IsOSX) { string bundleId = BundleIds[editorId]; @@ -81,7 +81,7 @@ namespace GodotTools.Ides.MonoDevelop public Instance(string solutionFile, EditorId editorId) { - if (editorId == EditorId.VisualStudioForMac && !OS.IsOSX()) + if (editorId == EditorId.VisualStudioForMac && !OS.IsOSX) throw new InvalidOperationException($"{nameof(EditorId.VisualStudioForMac)} not supported on this platform"); this.solutionFile = solutionFile; @@ -93,7 +93,7 @@ namespace GodotTools.Ides.MonoDevelop static Instance() { - if (OS.IsOSX()) + if (OS.IsOSX) { ExecutableNames = new Dictionary<EditorId, string> { @@ -107,7 +107,7 @@ namespace GodotTools.Ides.MonoDevelop {EditorId.VisualStudioForMac, "com.microsoft.visual-studio"} }; } - else if (OS.IsWindows()) + else if (OS.IsWindows) { ExecutableNames = new Dictionary<EditorId, string> { @@ -118,7 +118,7 @@ namespace GodotTools.Ides.MonoDevelop {EditorId.MonoDevelop, "MonoDevelop.exe"} }; } - else if (OS.IsUnix()) + else if (OS.IsUnixLike()) { ExecutableNames = new Dictionary<EditorId, string> { diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs index 836c9c11e4..de361ba844 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs @@ -52,7 +52,7 @@ namespace GodotTools.Internals public static void ScriptEditorDebugger_ReloadScripts() => internal_ScriptEditorDebugger_ReloadScripts(); - // Internal Calls + #region Internal [MethodImpl(MethodImplOptions.InternalCall)] private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config); @@ -110,5 +110,7 @@ namespace GodotTools.Internals [MethodImpl(MethodImplOptions.InternalCall)] private static extern void internal_ScriptEditorDebugger_ReloadScripts(); + + #endregion } } diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index e48b1115db..21ee85f2a9 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -1,72 +1,94 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Runtime.CompilerServices; namespace GodotTools.Utils { + [SuppressMessage("ReSharper", "InconsistentNaming")] public static class OS { [MethodImpl(MethodImplOptions.InternalCall)] - extern static string GetPlatformName(); + static extern string GetPlatformName(); - const string HaikuName = "Haiku"; - const string OSXName = "OSX"; - const string ServerName = "Server"; - const string UWPName = "UWP"; - const string WindowsName = "Windows"; - const string X11Name = "X11"; - - public static bool IsHaiku() + public static class Names { - return HaikuName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + public const string Windows = "Windows"; + public const string OSX = "OSX"; + public const string X11 = "X11"; + public const string Server = "Server"; + public const string UWP = "UWP"; + public const string Haiku = "Haiku"; + public const string Android = "Android"; + public const string HTML5 = "HTML5"; } - public static bool IsOSX() + public static class Platforms { - return OSXName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + public const string Windows = "windows"; + public const string OSX = "osx"; + public const string X11 = "x11"; + public const string Server = "server"; + public const string UWP = "uwp"; + public const string Haiku = "haiku"; + public const string Android = "android"; + public const string HTML5 = "javascript"; } - public static bool IsServer() + public static readonly Dictionary<string, string> PlatformNameMap = new Dictionary<string, string> { - return ServerName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); - } - - public static bool IsUWP() + [Names.Windows] = Platforms.Windows, + [Names.OSX] = Platforms.OSX, + [Names.X11] = Platforms.X11, + [Names.Server] = Platforms.Server, + [Names.UWP] = Platforms.UWP, + [Names.Haiku] = Platforms.Haiku, + [Names.Android] = Platforms.Android, + [Names.HTML5] = Platforms.HTML5 + }; + + private static bool IsOS(string name) { - return UWPName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); + return name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); } - public static bool IsWindows() - { - return WindowsName.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); - } + public static bool IsWindows => IsOS(Names.Windows); - public static bool IsX11() - { - return X11Name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase); - } + public static bool IsOSX => IsOS(Names.OSX); + + public static bool IsX11 => IsOS(Names.X11); + + public static bool IsServer => IsOS(Names.Server); + + public static bool IsUWP => IsOS(Names.UWP); + + public static bool IsHaiku => IsOS(Names.Haiku); + + public static bool IsAndroid => IsOS(Names.Android); + + public static bool IsHTML5 => IsOS(Names.HTML5); private static bool? _isUnixCache; - private static readonly string[] UnixPlatforms = {HaikuName, OSXName, ServerName, X11Name}; + private static readonly string[] UnixLikePlatforms = {Names.OSX, Names.X11, Names.Server, Names.Haiku, Names.Android}; - public static bool IsUnix() + public static bool IsUnixLike() { if (_isUnixCache.HasValue) return _isUnixCache.Value; string osName = GetPlatformName(); - _isUnixCache = UnixPlatforms.Any(p => p.Equals(osName, StringComparison.OrdinalIgnoreCase)); + _isUnixCache = UnixLikePlatforms.Any(p => p.Equals(osName, StringComparison.OrdinalIgnoreCase)); return _isUnixCache.Value; } - public static char PathSep => IsWindows() ? ';' : ':'; + public static char PathSep => IsWindows ? ';' : ':'; public static string PathWhich(string name) { - string[] windowsExts = IsWindows() ? Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) : null; + string[] windowsExts = IsWindows ? Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) : null; string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep); var searchDirs = new List<string>(); @@ -80,7 +102,7 @@ namespace GodotTools.Utils { string path = Path.Combine(dir, name); - if (IsWindows() && windowsExts != null) + if (IsWindows && windowsExts != null) { foreach (var extension in windowsExts) { @@ -102,12 +124,14 @@ namespace GodotTools.Utils public static void RunProcess(string command, IEnumerable<string> arguments) { + // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead string CmdLineArgsToString(IEnumerable<string> args) { + // Not perfect, but as long as we are careful... return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg)); } - ProcessStartInfo startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments)) + var startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments)) { RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 28cab2ab61..2252f7676d 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -97,7 +97,7 @@ #define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type #define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array" -#define BINDINGS_GENERATOR_VERSION UINT32_C(9) +#define BINDINGS_GENERATOR_VERSION UINT32_C(11) const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n"); @@ -731,13 +731,26 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) { i++; } + String im_type_out = return_type->im_type_out; + + if (return_type->ret_as_byref_arg) { + // Doesn't affect the unique signature + im_type_out = "void"; + + im_sig += ", "; + im_sig += return_type->im_type_out; + im_sig += " argRet"; + + i++; + } + // godot_icall_{argc}_{icallcount} String icall_method = ICALL_PREFIX; icall_method += itos(imethod.arguments.size()); icall_method += "_"; icall_method += itos(method_icalls.size()); - InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, return_type->im_type_out, im_sig, im_unique_sig); + InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, im_type_out, im_sig, im_unique_sig); List<InternalCall>::Element *match = method_icalls.find(im_icall); @@ -1685,17 +1698,18 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf const InternalCall *im_icall = match->value(); String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS; - im_call += "." + im_icall->name + "(" + icall_params + ")"; + im_call += "."; + im_call += im_icall->name; if (p_imethod.arguments.size()) p_output.append(cs_in_statements); if (return_type->cname == name_cache.type_void) { - p_output.append(im_call + ";\n"); + p_output.append(im_call + "(" + icall_params + ");\n"); } else if (return_type->cs_out.empty()) { - p_output.append("return " + im_call + ";\n"); + p_output.append("return " + im_call + "(" + icall_params + ");\n"); } else { - p_output.append(sformat(return_type->cs_out, im_call, return_type->cs_type, return_type->im_type_out)); + p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_type->cs_type, return_type->im_type_out)); p_output.append("\n"); } @@ -1937,6 +1951,15 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte i++; } + if (return_type->ret_as_byref_arg) { + c_func_sig += ", "; + c_func_sig += return_type->c_type_in; + c_func_sig += " "; + c_func_sig += "arg_ret"; + + i++; + } + const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod); ERR_FAIL_NULL_V(match, ERR_BUG); @@ -1951,14 +1974,12 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte // Generate icall function - p_output.append(ret_void ? "void " : return_type->c_type_out + " "); + p_output.append((ret_void || return_type->ret_as_byref_arg) ? "void " : return_type->c_type_out + " "); p_output.append(icall_method); p_output.append("("); p_output.append(c_func_sig); p_output.append(") " OPEN_BLOCK); - String fail_ret = ret_void ? "" : ", " + (return_type->c_type_out.ends_with("*") ? "NULL" : return_type->c_type_out + "()"); - if (!ret_void) { String ptrcall_return_type; String initialization; @@ -1982,9 +2003,18 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte p_output.append("\t" + ptrcall_return_type); p_output.append(" " C_LOCAL_RET); p_output.append(initialization + ";\n"); - p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE); - p_output.append(fail_ret); - p_output.append(");\n"); + + String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "NULL" : return_type->c_type_out + "()"; + + if (return_type->ret_as_byref_arg) { + p_output.append("\tif (" CS_PARAM_INSTANCE " == NULL) { *arg_ret = "); + p_output.append(fail_ret); + p_output.append("; ERR_FAIL_MSG(\"Parameter ' arg_ret ' is null.\"); }\n"); + } else { + p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", "); + p_output.append(fail_ret); + p_output.append(");\n"); + } } else { p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n"); } @@ -2045,10 +2075,13 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } if (!ret_void) { - if (return_type->c_out.empty()) + if (return_type->c_out.empty()) { p_output.append("\treturn " C_LOCAL_RET ";\n"); - else + } else if (return_type->ret_as_byref_arg) { + p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name, "arg_ret")); + } else { p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name)); + } } p_output.append(CLOSE_BLOCK "\n"); @@ -2620,30 +2653,32 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { TypeInterface itype; -#define INSERT_STRUCT_TYPE(m_type, m_type_in) \ +#define INSERT_STRUCT_TYPE(m_type) \ { \ itype = TypeInterface::create_value_type(String(#m_type)); \ itype.c_in = "\t%0 %1_in = MARSHALLED_IN(" #m_type ", %1);\n"; \ - itype.c_out = "\treturn MARSHALLED_OUT(" #m_type ", %1);\n"; \ + itype.c_out = "\t*%3 = MARSHALLED_OUT(" #m_type ", %1);\n"; \ itype.c_arg_in = "&%s_in"; \ itype.c_type_in = "GDMonoMarshal::M_" #m_type "*"; \ itype.c_type_out = "GDMonoMarshal::M_" #m_type; \ itype.cs_in = "ref %s"; \ - itype.cs_out = "return (%1)%0;"; \ - itype.im_type_out = itype.cs_type; \ + /* in cs_out, im_type_out (%3) includes the 'out ' part */ \ + itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; \ + itype.im_type_out = "out " + itype.cs_type; \ + itype.ret_as_byref_arg = true; \ builtin_types.insert(itype.cname, itype); \ } - INSERT_STRUCT_TYPE(Vector2, "real_t*") - INSERT_STRUCT_TYPE(Rect2, "real_t*") - INSERT_STRUCT_TYPE(Transform2D, "real_t*") - INSERT_STRUCT_TYPE(Vector3, "real_t*") - INSERT_STRUCT_TYPE(Basis, "real_t*") - INSERT_STRUCT_TYPE(Quat, "real_t*") - INSERT_STRUCT_TYPE(Transform, "real_t*") - INSERT_STRUCT_TYPE(AABB, "real_t*") - INSERT_STRUCT_TYPE(Color, "real_t*") - INSERT_STRUCT_TYPE(Plane, "real_t*") + INSERT_STRUCT_TYPE(Vector2) + INSERT_STRUCT_TYPE(Rect2) + INSERT_STRUCT_TYPE(Transform2D) + INSERT_STRUCT_TYPE(Vector3) + INSERT_STRUCT_TYPE(Basis) + INSERT_STRUCT_TYPE(Quat) + INSERT_STRUCT_TYPE(Transform) + INSERT_STRUCT_TYPE(AABB) + INSERT_STRUCT_TYPE(Color) + INSERT_STRUCT_TYPE(Plane) #undef INSERT_STRUCT_TYPE @@ -2687,11 +2722,44 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { INSERT_INT_TYPE("sbyte", int8_t, int64_t); INSERT_INT_TYPE("short", int16_t, int64_t); INSERT_INT_TYPE("int", int32_t, int64_t); - INSERT_INT_TYPE("long", int64_t, int64_t); INSERT_INT_TYPE("byte", uint8_t, int64_t); INSERT_INT_TYPE("ushort", uint16_t, int64_t); INSERT_INT_TYPE("uint", uint32_t, int64_t); - INSERT_INT_TYPE("ulong", uint64_t, int64_t); + + itype = TypeInterface::create_value_type(String("long")); + { + itype.c_out = "\treturn (%0)%1;\n"; + itype.c_in = "\t%0 %1_in = (%0)*%1;\n"; + itype.c_out = "\t*%3 = (%0)%1;\n"; + itype.c_type = "int64_t"; + itype.c_arg_in = "&%s_in"; + } + itype.c_type_in = "int64_t*"; + itype.c_type_out = "int64_t"; + itype.im_type_in = "ref " + itype.name; + itype.im_type_out = "out " + itype.name; + itype.cs_in = "ref %0"; + /* in cs_out, im_type_out (%3) includes the 'out ' part */ + itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.ret_as_byref_arg = true; + builtin_types.insert(itype.cname, itype); + + itype = TypeInterface::create_value_type(String("ulong")); + { + itype.c_in = "\t%0 %1_in = (%0)*%1;\n"; + itype.c_out = "\t*%3 = (%0)%1;\n"; + itype.c_type = "int64_t"; + itype.c_arg_in = "&%s_in"; + } + itype.c_type_in = "uint64_t*"; + itype.c_type_out = "uint64_t"; + itype.im_type_in = "ref " + itype.name; + itype.im_type_out = "out " + itype.name; + itype.cs_in = "ref %0"; + /* in cs_out, im_type_out (%3) includes the 'out ' part */ + itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.ret_as_byref_arg = true; + builtin_types.insert(itype.cname, itype); } // Floating point types @@ -2703,16 +2771,20 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.proxy_name = "float"; { // The expected type for 'float' in ptrcall is 'double' - itype.c_in = "\t%0 %1_in = (%0)%1;\n"; - itype.c_out = "\treturn (%0)%1;\n"; + itype.c_in = "\t%0 %1_in = (%0)*%1;\n"; + itype.c_out = "\t*%3 = (%0)%1;\n"; itype.c_type = "double"; - itype.c_type_in = "float"; + itype.c_type_in = "float*"; itype.c_type_out = "float"; itype.c_arg_in = "&%s_in"; } itype.cs_type = itype.proxy_name; - itype.im_type_in = itype.proxy_name; - itype.im_type_out = itype.proxy_name; + itype.im_type_in = "ref " + itype.proxy_name; + itype.im_type_out = "out " + itype.proxy_name; + itype.cs_in = "ref %0"; + /* in cs_out, im_type_out (%3) includes the 'out ' part */ + itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.ret_as_byref_arg = true; builtin_types.insert(itype.cname, itype); // double @@ -2720,13 +2792,21 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.name = "double"; itype.cname = itype.name; itype.proxy_name = "double"; - itype.c_type = "double"; - itype.c_type_in = "double"; - itype.c_type_out = "double"; - itype.c_arg_in = "&%s"; + { + itype.c_in = "\t%0 %1_in = (%0)*%1;\n"; + itype.c_out = "\t*%3 = (%0)%1;\n"; + itype.c_type = "double"; + itype.c_type_in = "double*"; + itype.c_type_out = "double"; + itype.c_arg_in = "&%s_in"; + } itype.cs_type = itype.proxy_name; - itype.im_type_in = itype.proxy_name; - itype.im_type_out = itype.proxy_name; + itype.im_type_in = "ref " + itype.proxy_name; + itype.im_type_out = "out " + itype.proxy_name; + itype.cs_in = "ref %0"; + /* in cs_out, im_type_out (%3) includes the 'out ' part */ + itype.cs_out = "%0(%1, %3 argRet); return (%2)argRet;"; + itype.ret_as_byref_arg = true; builtin_types.insert(itype.cname, itype); } @@ -2757,7 +2837,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; itype.cs_in = "NodePath." CS_SMETHOD_GETINSTANCE "(%0)"; - itype.cs_out = "return new %1(%0);"; + itype.cs_out = "return new %2(%0(%1));"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -2773,7 +2853,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type + "*"; itype.cs_type = itype.proxy_name; itype.cs_in = "RID." CS_SMETHOD_GETINSTANCE "(%0)"; - itype.cs_out = "return new %1(%0);"; + itype.cs_out = "return new %2(%0(%1));"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -2855,7 +2935,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type + "*"; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; - itype.cs_out = "return new " + itype.cs_type + "(%0);"; + itype.cs_out = "return new " + itype.cs_type + "(%0(%1));"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); @@ -2871,7 +2951,7 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { itype.c_type_out = itype.c_type + "*"; itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name; itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()"; - itype.cs_out = "return new " + itype.cs_type + "(%0);"; + itype.cs_out = "return new " + itype.cs_type + "(%0(%1));"; itype.im_type_in = "IntPtr"; itype.im_type_out = "IntPtr"; builtin_types.insert(itype.cname, itype); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 8f3676940b..07918a2d03 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -214,6 +214,14 @@ class BindingsGenerator { */ bool memory_own; + /** + * This must be set to true for any struct bigger than 32-bits. Those cannot be passed/returned by value + * with internal calls, so we must use pointers instead. Returns must be replace with out parameters. + * In this case, [c_out] and [cs_out] must have a different format, explained below. + * The Mono IL interpreter icall trampolines don't support passing structs bigger than 32-bits by value (at least not on WASM). + */ + bool ret_as_byref_arg; + // !! The comments of the following fields make reference to other fields via square brackets, e.g.: [field_name] // !! When renaming those fields, make sure to rename their references in the comments @@ -248,6 +256,14 @@ class BindingsGenerator { * %0: [c_type_out] of the return type * %1: name of the variable to be returned * %2: [name] of the return type + * --------------------------------------- + * If [ret_as_byref_arg] is true, the format is different. Instead of using a return statement, + * the value must be assigned to a parameter. This type of this parameter is a pointer to [c_type_out]. + * Formatting elements: + * %0: [c_type_out] of the return type + * %1: name of the variable to be returned + * %2: [name] of the return type + * %3: name of the parameter that must be assigned the return value */ String c_out; @@ -291,9 +307,10 @@ class BindingsGenerator { * One or more statements that determine how a variable of this type is returned from a method. * It must contain the return statement(s). * Formatting elements: - * %0: internal method call statement - * %1: [cs_type] of the return type - * %2: [im_type_out] of the return type + * %0: internal method name + * %1: internal method call arguments without surrounding parenthesis + * %2: [cs_type] of the return type + * %3: [im_type_out] of the return type */ String cs_out; @@ -417,7 +434,7 @@ class BindingsGenerator { r_enum_itype.cs_type = r_enum_itype.proxy_name; r_enum_itype.cs_in = "(int)%s"; - r_enum_itype.cs_out = "return (%1)%0;"; + r_enum_itype.cs_out = "return (%2)%0(%1);"; r_enum_itype.im_type_in = "int"; r_enum_itype.im_type_out = "int"; r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name]; @@ -435,6 +452,8 @@ class BindingsGenerator { memory_own = false; + ret_as_byref_arg = false; + c_arg_in = "%s"; class_doc = NULL; diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 1564d73c2a..4055ec005a 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -219,15 +219,15 @@ int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObje return err; } -uint32_t godot_icall_GodotSharpExport_GetExportedAssemblyDependencies(MonoString *p_project_dll_name, MonoString *p_project_dll_src_path, - MonoString *p_build_config, MonoString *p_custom_lib_dir, MonoObject *r_dependencies) { +uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoString *p_project_dll_name, MonoString *p_project_dll_src_path, + MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_dependencies) { String project_dll_name = GDMonoMarshal::mono_string_to_godot(p_project_dll_name); String project_dll_src_path = GDMonoMarshal::mono_string_to_godot(p_project_dll_src_path); String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config); - String custom_lib_dir = GDMonoMarshal::mono_string_to_godot(p_custom_lib_dir); + String custom_bcl_dir = GDMonoMarshal::mono_string_to_godot(p_custom_bcl_dir); Dictionary dependencies = GDMonoMarshal::mono_object_to_variant(r_dependencies); - return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_lib_dir, dependencies); + return GodotSharpExport::get_exported_assembly_dependencies(project_dll_name, project_dll_src_path, build_config, custom_bcl_dir, dependencies); } MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) { @@ -411,8 +411,8 @@ void register_editor_internal_calls() { // ScriptClassParser mono_add_internal_call("GodotTools.Internals.ScriptClassParser::internal_ParseFile", (void *)godot_icall_ScriptClassParser_ParseFile); - // GodotSharpExport - mono_add_internal_call("GodotTools.GodotSharpExport::internal_GetExportedAssemblyDependencies", (void *)godot_icall_GodotSharpExport_GetExportedAssemblyDependencies); + // ExportPlugin + mono_add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", (void *)godot_icall_ExportPlugin_GetExportedAssemblyDependencies); // Internals mono_add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", (void *)godot_icall_Internal_UpdateApiAssembliesFromPrebuilt); diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index e83152d668..9ae9399e1d 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -36,6 +36,7 @@ #include "../mono_gd/gd_mono.h" #include "../mono_gd/gd_mono_assembly.h" +#include "../mono_gd/gd_mono_cache.h" namespace GodotSharpExport { diff --git a/modules/mono/glue/Managed/Files/NodePath.cs b/modules/mono/glue/Managed/Files/NodePath.cs index 4de4e1e6a9..8c5872ba5a 100644 --- a/modules/mono/glue/Managed/Files/NodePath.cs +++ b/modules/mono/glue/Managed/Files/NodePath.cs @@ -12,7 +12,7 @@ namespace Godot internal static IntPtr GetPtr(NodePath instance) { if (instance == null) - return IntPtr.Zero; + throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null."); if (instance.disposed) throw new ObjectDisposedException(instance.GetType().FullName); diff --git a/modules/mono/glue/Managed/Files/RID.cs b/modules/mono/glue/Managed/Files/RID.cs index 12064beca2..94761531b1 100644 --- a/modules/mono/glue/Managed/Files/RID.cs +++ b/modules/mono/glue/Managed/Files/RID.cs @@ -12,7 +12,7 @@ namespace Godot internal static IntPtr GetPtr(RID instance) { if (instance == null) - return IntPtr.Zero; + throw new NullReferenceException($"The instance of type {nameof(RID)} is null."); if (instance.disposed) throw new ObjectDisposedException(instance.GetType().FullName); diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 6d85f55b97..2488f78350 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -36,6 +36,7 @@ #include "core/string_name.h" #include "../csharp_script.h" +#include "../mono_gd/gd_mono_cache.h" #include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_internals.h" #include "../mono_gd/gd_mono_utils.h" diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index e67c8b9ad9..bfb7b0f775 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -34,6 +34,7 @@ #include <mono/metadata/exception.h> +#include "../mono_gd/gd_mono_cache.h" #include "../mono_gd/gd_mono_class.h" #include "../mono_gd/gd_mono_utils.h" diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp index 8b9a1380d8..1381d79e2e 100644 --- a/modules/mono/glue/gd_glue.cpp +++ b/modules/mono/glue/gd_glue.cpp @@ -39,6 +39,7 @@ #include "core/variant.h" #include "core/variant_parser.h" +#include "../mono_gd/gd_mono_cache.h" #include "../mono_gd/gd_mono_utils.h" MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) { @@ -211,7 +212,7 @@ MonoString *godot_icall_GD_var2str(MonoObject *p_var) { } MonoObject *godot_icall_DefaultGodotTaskScheduler() { - return GDMonoUtils::mono_cache.task_scheduler_handle->get_target(); + return GDMonoCache::cached_data.task_scheduler_handle->get_target(); } void godot_register_gd_icalls() { diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 5fa8aed5a9..cb0ac9431e 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -39,8 +39,8 @@ #include "editor/editor_settings.h" #endif -#ifdef __ANDROID__ -#include "utils/android_utils.h" +#ifdef ANDROID_ENABLED +#include "mono_gd/gd_mono_android.h" #endif #include "mono_gd/gd_mono.h" @@ -130,7 +130,11 @@ private: res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin"); res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config()); +#ifdef JAVASCRIPT_ENABLED + mono_user_dir = "user://"; +#else mono_user_dir = _get_mono_user_dir(); +#endif mono_logs_dir = mono_user_dir.plus_file("mono_logs"); #ifdef TOOLS_ENABLED @@ -160,8 +164,8 @@ private: String data_mono_root_dir = data_dir_root.plus_file("Mono"); data_mono_etc_dir = data_mono_root_dir.plus_file("etc"); -#if __ANDROID__ - data_mono_lib_dir = GDMonoUtils::Android::get_app_native_lib_dir(); +#ifdef ANDROID_ENABLED + data_mono_lib_dir = GDMonoAndroid::get_app_native_lib_dir(); #else data_mono_lib_dir = data_mono_root_dir.plus_file("lib"); #endif @@ -197,8 +201,8 @@ private: String data_mono_root_dir = data_dir_root.plus_file("Mono"); data_mono_etc_dir = data_mono_root_dir.plus_file("etc"); -#if __ANDROID__ - data_mono_lib_dir = GDMonoUtils::Android::get_app_native_lib_dir(); +#ifdef ANDROID_ENABLED + data_mono_lib_dir = GDMonoAndroid::get_app_native_lib_dir(); #else data_mono_lib_dir = data_mono_root_dir.plus_file("lib"); #endif diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 504b8d41d0..384ef08cd0 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -46,6 +46,7 @@ #include "../csharp_script.h" #include "../godotsharp_dirs.h" #include "../utils/path_utils.h" +#include "gd_mono_cache.h" #include "gd_mono_class.h" #include "gd_mono_marshal.h" #include "gd_mono_utils.h" @@ -56,13 +57,26 @@ #ifdef ANDROID_ENABLED #include "android_mono_config.h" +#include "gd_mono_android.h" #endif +// TODO: +// This has turn into a gigantic mess. There's too much going on here. Too much #ifdef as well. +// It's just painful to read... It needs to be re-structured. Please, clean this up, future me. + GDMono *GDMono::singleton = NULL; namespace { -void setup_runtime_main_args() { +#if defined(JAVASCRIPT_ENABLED) +extern "C" { +void mono_wasm_load_runtime(const char *managed_path, int enable_debugging); +} +#endif + +#if !defined(JAVASCRIPT_ENABLED) + +void gd_mono_setup_runtime_main_args() { CharString execpath = OS::get_singleton()->get_executable_path().utf8(); List<String> cmdline_args = OS::get_singleton()->get_cmdline_args(); @@ -83,7 +97,7 @@ void setup_runtime_main_args() { mono_runtime_set_main_args(main_args.size(), main_args.ptrw()); } -void gdmono_profiler_init() { +void gd_mono_profiler_init() { String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd"); bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false); if (profiler_enabled) { @@ -91,9 +105,9 @@ void gdmono_profiler_init() { } } -#ifdef DEBUG_ENABLED +#if defined(DEBUG_ENABLED) -bool _wait_for_debugger_msecs(uint32_t p_msecs) { +bool gd_mono_wait_for_debugger_msecs(uint32_t p_msecs) { do { if (mono_is_debugger_attached()) @@ -115,7 +129,7 @@ bool _wait_for_debugger_msecs(uint32_t p_msecs) { return mono_is_debugger_attached(); } -void gdmono_debug_init() { +void gd_mono_debug_init() { mono_debug_init(MONO_DEBUG_FORMAT_MONO); @@ -151,11 +165,37 @@ void gdmono_debug_init() { mono_jit_parse_options(2, (char **)options); } +#endif // defined(DEBUG_ENABLED) +#endif // !defined(JAVASCRIPT_ENABLED) + +#if defined(JAVASCRIPT_ENABLED) +MonoDomain *gd_initialize_mono_runtime() { + const char *vfs_prefix = "managed"; + int enable_debugging = 0; + +#ifdef DEBUG_ENABLED + enable_debugging = 1; +#endif + + mono_wasm_load_runtime(vfs_prefix, enable_debugging); + + return mono_get_root_domain(); +} +#else +MonoDomain *gd_initialize_mono_runtime() { +#ifdef DEBUG_ENABLED + gd_mono_debug_init(); +#endif + + return mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319"); +} #endif } // namespace void GDMono::add_mono_shared_libs_dir_to_path() { + // TODO: Replace this with a mono_dl_fallback + // By default Mono seems to search shared libraries in the following directories: // Current working directory, @executable_path@ and PATH // The parent directory of the image file (assembly where the dllimport method is declared) @@ -279,11 +319,17 @@ void GDMono::initialize() { config_dir = bundled_config_dir; #endif // TOOLS_ENABLED +#if !defined(JAVASCRIPT_ENABLED) // Leak if we call mono_set_dirs more than once mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : NULL, config_dir.length() ? config_dir.utf8().get_data() : NULL); add_mono_shared_libs_dir_to_path(); +#endif + +#if defined(ANDROID_ENABLED) + GDMonoAndroid::register_android_dl_fallback(); +#endif { PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/unhandled_exception_policy", PROPERTY_HINT_ENUM, @@ -299,10 +345,8 @@ void GDMono::initialize() { GDMonoAssembly::initialize(); - gdmono_profiler_init(); - -#ifdef DEBUG_ENABLED - gdmono_debug_init(); +#if !defined(JAVASCRIPT_ENABLED) + gd_mono_profiler_init(); #endif #ifdef ANDROID_ENABLED @@ -326,12 +370,14 @@ void GDMono::initialize() { } #endif - root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319"); + root_domain = gd_initialize_mono_runtime(); ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime."); GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread()); - setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs +#if !defined(JAVASCRIPT_ENABLED) + gd_mono_setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs +#endif runtime_initialized = true; @@ -344,8 +390,8 @@ void GDMono::initialize() { Error domain_load_err = _load_scripts_domain(); ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain."); -#ifdef DEBUG_ENABLED - bool debugger_attached = _wait_for_debugger_msecs(500); +#if defined(DEBUG_ENABLED) && !defined(JAVASCRIPT_ENABLED) + bool debugger_attached = gd_mono_wait_for_debugger_msecs(500); if (!debugger_attached && OS::get_singleton()->is_stdout_verbose()) print_error("Mono: Debugger wait timeout"); #endif @@ -381,7 +427,7 @@ void GDMono::initialize_load_assemblies() { } bool GDMono::_are_api_assemblies_out_of_sync() { - bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoUtils::mono_cache.godot_api_cache_updated); + bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoCache::cached_data.godot_api_cache_updated); #ifdef TOOLS_ENABLED if (!out_of_sync) out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync; @@ -561,7 +607,7 @@ bool GDMono::_load_corlib_assembly() { bool success = load_assembly("mscorlib", &corlib_assembly); if (success) - GDMonoUtils::update_corlib_cache(); + GDMonoCache::update_corlib_cache(); return success; } @@ -834,9 +880,9 @@ bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, Lo } bool GDMono::_on_core_api_assembly_loaded() { - GDMonoUtils::update_godot_api_cache(); + GDMonoCache::update_godot_api_cache(); - if (!GDMonoUtils::mono_cache.godot_api_cache_updated) + if (!GDMonoCache::cached_data.godot_api_cache_updated) return false; get_singleton()->_install_trace_listener(); @@ -884,7 +930,7 @@ void GDMono::_load_api_assemblies() { if (_are_api_assemblies_out_of_sync()) { if (core_api_assembly.out_of_sync) { ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync."); - } else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) { + } else if (!GDMonoCache::cached_data.godot_api_cache_updated) { ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed."); } @@ -984,7 +1030,7 @@ Error GDMono::_unload_scripts_domain() { mono_gc_collect(mono_gc_max_generation()); - GDMonoUtils::clear_godot_api_cache(); + GDMonoCache::clear_godot_api_cache(); _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain)); diff --git a/modules/mono/mono_gd/gd_mono_android.cpp b/modules/mono/mono_gd/gd_mono_android.cpp new file mode 100644 index 0000000000..42983e1821 --- /dev/null +++ b/modules/mono/mono_gd/gd_mono_android.cpp @@ -0,0 +1,116 @@ +#include "gd_mono_android.h" + +#if defined(ANDROID_ENABLED) + +#include <dlfcn.h> // dlopen, dlsym +#include <mono/utils/mono-dl-fallback.h> + +#include "core/os/os.h" +#include "core/ustring.h" +#include "platform/android/thread_jandroid.h" + +#include "../utils/path_utils.h" +#include "../utils/string_utils.h" + +namespace GDMonoAndroid { + +String app_native_lib_dir_cache; + +String determine_app_native_lib_dir() { + JNIEnv *env = ThreadAndroid::get_env(); + + jclass activityThreadClass = env->FindClass("android/app/ActivityThread"); + jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;"); + jobject activityThread = env->CallStaticObjectMethod(activityThreadClass, currentActivityThread); + jmethodID getApplication = env->GetMethodID(activityThreadClass, "getApplication", "()Landroid/app/Application;"); + jobject ctx = env->CallObjectMethod(activityThread, getApplication); + + jmethodID getApplicationInfo = env->GetMethodID(env->GetObjectClass(ctx), "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;"); + jobject applicationInfo = env->CallObjectMethod(ctx, getApplicationInfo); + jfieldID nativeLibraryDirField = env->GetFieldID(env->GetObjectClass(applicationInfo), "nativeLibraryDir", "Ljava/lang/String;"); + jstring nativeLibraryDir = (jstring)env->GetObjectField(applicationInfo, nativeLibraryDirField); + + String result; + + const char *const nativeLibraryDir_utf8 = env->GetStringUTFChars(nativeLibraryDir, NULL); + if (nativeLibraryDir_utf8) { + result.parse_utf8(nativeLibraryDir_utf8); + env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDir_utf8); + } + + return result; +} + +String get_app_native_lib_dir() { + if (app_native_lib_dir_cache.empty()) + app_native_lib_dir_cache = determine_app_native_lib_dir(); + return app_native_lib_dir_cache; +} + +int gd_mono_convert_dl_flags(int flags) { + // from mono's runtime-bootstrap.c + + int lflags = flags & MONO_DL_LOCAL ? 0 : RTLD_GLOBAL; + + if (flags & MONO_DL_LAZY) + lflags |= RTLD_LAZY; + else + lflags |= RTLD_NOW; + + return lflags; +} + +void *gd_mono_android_dlopen(const char *p_name, int p_flags, char **r_err, void *p_user_data) { + String name = String::utf8(p_name); + + if (name.ends_with(".dll.so") || name.ends_with(".exe.so")) { + String app_native_lib_dir = get_app_native_lib_dir(); + + String orig_so_name = name.get_file(); + String so_name = "lib-aot-" + orig_so_name; + String so_path = path::join(app_native_lib_dir, so_name); + + if (!FileAccess::exists(so_path)) { + if (OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->print("Cannot find shared library: '%s'\n", so_path.utf8().get_data()); + return NULL; + } + + int lflags = gd_mono_convert_dl_flags(p_flags); + + void *handle = dlopen(so_path.utf8().get_data(), lflags); + + if (!handle) { + if (OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->print("Failed to open shared library: '%s'. Error: '%s'\n", so_path.utf8().get_data(), dlerror()); + return NULL; + } + + if (OS::get_singleton()->is_stdout_verbose()) + OS::get_singleton()->print("Successfully loaded AOT shared library: '%s'\n", so_path.utf8().get_data()); + + return handle; + } + + return NULL; +} + +void *gd_mono_android_dlsym(void *p_handle, const char *p_name, char **r_err, void *p_user_data) { + void *sym_addr = dlsym(p_handle, p_name); + + if (sym_addr) + return sym_addr; + + if (r_err) + *r_err = str_format_new("%s\n", dlerror()); + + return NULL; +} + +void register_android_dl_fallback() { + mono_dl_fallback_register(gd_mono_android_dlopen, gd_mono_android_dlsym, NULL, NULL); +} + +} // namespace GDMonoAndroid + +#endif diff --git a/modules/mono/mono_gd/gd_mono_android.h b/modules/mono/mono_gd/gd_mono_android.h new file mode 100644 index 0000000000..52705fbd2d --- /dev/null +++ b/modules/mono/mono_gd/gd_mono_android.h @@ -0,0 +1,18 @@ +#ifndef GD_MONO_ANDROID_H +#define GD_MONO_ANDROID_H + +#if defined(ANDROID_ENABLED) + +#include "core/ustring.h" + +namespace GDMonoAndroid { + +String get_app_native_lib_dir(); + +void register_android_dl_fallback(); + +} // namespace GDMonoAndroid + +#endif // ANDROID_ENABLED + +#endif // GD_MONO_ANDROID_H diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index a82bb42731..91842420b7 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -39,6 +39,7 @@ #include "core/project_settings.h" #include "../godotsharp_dirs.h" +#include "gd_mono_cache.h" #include "gd_mono_class.h" bool GDMonoAssembly::no_search = false; diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp new file mode 100644 index 0000000000..3422e4ff58 --- /dev/null +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -0,0 +1,282 @@ +#include "gd_mono_cache.h" + +#include "gd_mono.h" +#include "gd_mono_class.h" +#include "gd_mono_marshal.h" +#include "gd_mono_method.h" +#include "gd_mono_utils.h" + +namespace GDMonoCache { + +CachedData cached_data; + +#define CACHE_AND_CHECK(m_var, m_val) \ + { \ + CRASH_COND(m_var != NULL); \ + m_var = m_val; \ + ERR_FAIL_COND_MSG(m_var == NULL, "Mono Cache: Member " #m_var " is null."); \ + } + +#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val) +#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_ns##_##m_class, m_val) +#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.rawclass_##m_class, m_val) +#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(cached_data.field_##m_class##_##m_field, m_val) +#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val) +#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val) + +#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \ + { \ + CRASH_COND(!m_var.is_null()); \ + ERR_FAIL_COND_MSG(m_val == NULL, "Mono Cache: Method for member " #m_var " is null."); \ + m_var.set_from_method(m_val); \ + ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \ + } + +#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val) + +void CachedData::clear_corlib_cache() { + + corlib_cache_updated = false; + + class_MonoObject = NULL; + class_bool = NULL; + class_int8_t = NULL; + class_int16_t = NULL; + class_int32_t = NULL; + class_int64_t = NULL; + class_uint8_t = NULL; + class_uint16_t = NULL; + class_uint32_t = NULL; + class_uint64_t = NULL; + class_float = NULL; + class_double = NULL; + class_String = NULL; + class_IntPtr = NULL; + + class_System_Collections_IEnumerable = NULL; + class_System_Collections_IDictionary = NULL; + +#ifdef DEBUG_ENABLED + class_System_Diagnostics_StackTrace = NULL; + methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify(); + method_System_Diagnostics_StackTrace_ctor_bool = NULL; + method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL; +#endif + + class_KeyNotFoundException = NULL; +} + +void CachedData::clear_godot_api_cache() { + + godot_api_cache_updated = false; + + rawclass_Dictionary = NULL; + + class_Vector2 = NULL; + class_Rect2 = NULL; + class_Transform2D = NULL; + class_Vector3 = NULL; + class_Basis = NULL; + class_Quat = NULL; + class_Transform = NULL; + class_AABB = NULL; + class_Color = NULL; + class_Plane = NULL; + class_NodePath = NULL; + class_RID = NULL; + class_GodotObject = NULL; + class_GodotResource = NULL; + class_Node = NULL; + class_Control = NULL; + class_Spatial = NULL; + class_WeakRef = NULL; + class_Array = NULL; + class_Dictionary = NULL; + class_MarshalUtils = NULL; + class_ISerializationListener = NULL; + +#ifdef DEBUG_ENABLED + class_DebuggingUtils = NULL; + methodthunk_DebuggingUtils_GetStackFrameInfo.nullify(); +#endif + + class_ExportAttribute = NULL; + field_ExportAttribute_hint = NULL; + field_ExportAttribute_hintString = NULL; + class_SignalAttribute = NULL; + class_ToolAttribute = NULL; + class_RemoteAttribute = NULL; + class_SyncAttribute = NULL; + class_MasterAttribute = NULL; + class_PuppetAttribute = NULL; + class_SlaveAttribute = NULL; + class_RemoteSyncAttribute = NULL; + class_MasterSyncAttribute = NULL; + class_PuppetSyncAttribute = NULL; + class_GodotMethodAttribute = NULL; + field_GodotMethodAttribute_methodName = NULL; + + field_GodotObject_ptr = NULL; + field_NodePath_ptr = NULL; + field_Image_ptr = NULL; + field_RID_ptr = NULL; + + methodthunk_GodotObject_Dispose.nullify(); + methodthunk_Array_GetPtr.nullify(); + methodthunk_Dictionary_GetPtr.nullify(); + methodthunk_SignalAwaiter_SignalCallback.nullify(); + methodthunk_SignalAwaiter_FailureCallback.nullify(); + methodthunk_GodotTaskScheduler_Activate.nullify(); + + // Start of MarshalUtils methods + + methodthunk_MarshalUtils_TypeIsGenericArray.nullify(); + methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify(); + + methodthunk_MarshalUtils_ArrayGetElementType.nullify(); + methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify(); + + methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType.nullify(); + methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType.nullify(); + methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info.nullify(); + methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info.nullify(); + + methodthunk_MarshalUtils_MakeGenericArrayType.nullify(); + methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify(); + + methodthunk_MarshalUtils_EnumerableToArray.nullify(); + methodthunk_MarshalUtils_IDictionaryToDictionary.nullify(); + methodthunk_MarshalUtils_GenericIDictionaryToDictionary.nullify(); + + // End of MarshalUtils methods + + task_scheduler_handle = Ref<MonoGCHandle>(); +} + +#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) +#define GODOT_API_NS_CLASS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class)) + +void update_corlib_cache() { + + CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class())); + CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class())); + CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class())); + CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class())); + CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class())); + CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class())); + CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class())); + CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class())); + CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class())); + CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class())); + CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class())); + CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class())); + CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class())); + CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class())); + + CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable")); + CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary")); + +#ifdef DEBUG_ENABLED + CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); + CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames")); + CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); + CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); +#endif + + CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException")); + + cached_data.corlib_cache_updated = true; +} + +void update_godot_api_cache() { + + CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2)); + CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2)); + CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D)); + CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3)); + CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis)); + CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat)); + CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform)); + CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB)); + CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color)); + CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane)); + CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); + CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID)); + CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); + CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource)); + CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); + CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); + CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); + CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); + CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)); + CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)); + CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); + CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener)); + +#ifdef DEBUG_ENABLED + CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils)); +#endif + + // Attributes + CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); + CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); + CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); + CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute)); + CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); + CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); + CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute)); + CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute)); + CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute)); + CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute)); + CACHE_CLASS_AND_CHECK(RemoteSyncAttribute, GODOT_API_CLASS(RemoteSyncAttribute)); + CACHE_CLASS_AND_CHECK(MasterSyncAttribute, GODOT_API_CLASS(MasterSyncAttribute)); + CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute)); + CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute)); + CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName")); + + CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD)); + CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD)); + CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD)); + + CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0)); + CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method("GetPtr", 0)); + CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method("GetPtr", 0)); + CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1)); + CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("FailureCallback", 0)); + CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0)); + + // Start of MarshalUtils methods + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIEnumerableIsAssignableFromType", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryIsAssignableFromType", 3)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2)); + + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, GODOT_API_CLASS(MarshalUtils)->get_method("EnumerableToArray", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("IDictionaryToDictionary", 2)); + CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("GenericIDictionaryToDictionary", 2)); + + // End of MarshalUtils methods + +#ifdef DEBUG_ENABLED + CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4)); +#endif + + // TODO Move to CSharpLanguage::init() and do handle disposal + MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); + GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler)); + cached_data.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); + + cached_data.godot_api_cache_updated = true; +} + +} // namespace GDMonoCache diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h new file mode 100644 index 0000000000..0ad7fb607c --- /dev/null +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -0,0 +1,174 @@ +#ifndef GD_MONO_CACHE_H +#define GD_MONO_CACHE_H + +#include "gd_mono_header.h" +#include "gd_mono_method_thunk.h" + +namespace GDMonoCache { + +struct CachedData { + + // ----------------------------------------------- + // corlib classes + + // Let's use the no-namespace format for these too + GDMonoClass *class_MonoObject; + GDMonoClass *class_bool; + GDMonoClass *class_int8_t; + GDMonoClass *class_int16_t; + GDMonoClass *class_int32_t; + GDMonoClass *class_int64_t; + GDMonoClass *class_uint8_t; + GDMonoClass *class_uint16_t; + GDMonoClass *class_uint32_t; + GDMonoClass *class_uint64_t; + GDMonoClass *class_float; + GDMonoClass *class_double; + GDMonoClass *class_String; + GDMonoClass *class_IntPtr; + + GDMonoClass *class_System_Collections_IEnumerable; + GDMonoClass *class_System_Collections_IDictionary; + +#ifdef DEBUG_ENABLED + GDMonoClass *class_System_Diagnostics_StackTrace; + GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool; + GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool; +#endif + + GDMonoClass *class_KeyNotFoundException; + + MonoClass *rawclass_Dictionary; + // ----------------------------------------------- + + GDMonoClass *class_Vector2; + GDMonoClass *class_Rect2; + GDMonoClass *class_Transform2D; + GDMonoClass *class_Vector3; + GDMonoClass *class_Basis; + GDMonoClass *class_Quat; + GDMonoClass *class_Transform; + GDMonoClass *class_AABB; + GDMonoClass *class_Color; + GDMonoClass *class_Plane; + GDMonoClass *class_NodePath; + GDMonoClass *class_RID; + GDMonoClass *class_GodotObject; + GDMonoClass *class_GodotResource; + GDMonoClass *class_Node; + GDMonoClass *class_Control; + GDMonoClass *class_Spatial; + GDMonoClass *class_WeakRef; + GDMonoClass *class_Array; + GDMonoClass *class_Dictionary; + GDMonoClass *class_MarshalUtils; + GDMonoClass *class_ISerializationListener; + +#ifdef DEBUG_ENABLED + GDMonoClass *class_DebuggingUtils; + GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo; +#endif + + GDMonoClass *class_ExportAttribute; + GDMonoField *field_ExportAttribute_hint; + GDMonoField *field_ExportAttribute_hintString; + GDMonoClass *class_SignalAttribute; + GDMonoClass *class_ToolAttribute; + GDMonoClass *class_RemoteAttribute; + GDMonoClass *class_SyncAttribute; + GDMonoClass *class_RemoteSyncAttribute; + GDMonoClass *class_MasterSyncAttribute; + GDMonoClass *class_PuppetSyncAttribute; + GDMonoClass *class_MasterAttribute; + GDMonoClass *class_PuppetAttribute; + GDMonoClass *class_SlaveAttribute; + GDMonoClass *class_GodotMethodAttribute; + GDMonoField *field_GodotMethodAttribute_methodName; + + GDMonoField *field_GodotObject_ptr; + GDMonoField *field_NodePath_ptr; + GDMonoField *field_Image_ptr; + GDMonoField *field_RID_ptr; + + GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose; + GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr; + GDMonoMethodThunkR<Dictionary *, MonoObject *> methodthunk_Dictionary_GetPtr; + GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback; + GDMonoMethodThunk<MonoObject *> methodthunk_SignalAwaiter_FailureCallback; + GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate; + + // Start of MarshalUtils methods + + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary; + + GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType; + GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; + + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info; + GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info; + + GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType; + GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType; + + GDMonoMethodThunk<MonoObject *, Array *> methodthunk_MarshalUtils_EnumerableToArray; + GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_IDictionaryToDictionary; + GDMonoMethodThunk<MonoObject *, Dictionary *> methodthunk_MarshalUtils_GenericIDictionaryToDictionary; + + // End of MarshalUtils methods + + Ref<MonoGCHandle> task_scheduler_handle; + + bool corlib_cache_updated; + bool godot_api_cache_updated; + + void clear_corlib_cache(); + void clear_godot_api_cache(); + + CachedData() { + clear_corlib_cache(); + clear_godot_api_cache(); + } +}; + +extern CachedData cached_data; + +void update_corlib_cache(); +void update_godot_api_cache(); + +inline void clear_corlib_cache() { + cached_data.clear_corlib_cache(); +} + +inline void clear_godot_api_cache() { + cached_data.clear_godot_api_cache(); +} + +_FORCE_INLINE_ bool tools_godot_api_check() { +#ifdef TOOLS_ENABLED + return cached_data.godot_api_cache_updated; +#else + return true; // Assume it's updated if this was called, otherwise it's a bug +#endif +} + +} // namespace GDMonoCache + +#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class) +#define CACHED_CLASS_RAW(m_class) (GDMonoCache::cached_data.class_##m_class->get_mono_ptr()) +#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoCache::cached_data.rawclass_##m_class) +#define CACHED_FIELD(m_class, m_field) (GDMonoCache::cached_data.field_##m_class##_##m_field) +#define CACHED_METHOD(m_class, m_method) (GDMonoCache::cached_data.method_##m_class##_##m_method) +#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method) +#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property) + +#ifdef REAL_T_IS_DOUBLE +#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double) +#else +#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float) +#endif + +#endif // GD_MONO_CACHE_H diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp index 89a88fcfb2..fb9b6be3d4 100644 --- a/modules/mono/mono_gd/gd_mono_class.cpp +++ b/modules/mono/mono_gd/gd_mono_class.cpp @@ -33,6 +33,7 @@ #include <mono/metadata/attrdefs.h> #include "gd_mono_assembly.h" +#include "gd_mono_cache.h" #include "gd_mono_marshal.h" String GDMonoClass::get_full_name(MonoClass *p_mono_class) { @@ -332,12 +333,6 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo return get_method(method); } -void *GDMonoClass::get_method_thunk(const StringName &p_name, int p_params_count) { - - GDMonoMethod *method = get_method(p_name, p_params_count); - return method ? method->get_thunk() : NULL; -} - GDMonoField *GDMonoClass::get_field(const StringName &p_name) { Map<StringName, GDMonoField *>::Element *result = fields.find(p_name); diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h index 40e1574927..562c337822 100644 --- a/modules/mono/mono_gd/gd_mono_class.h +++ b/modules/mono/mono_gd/gd_mono_class.h @@ -144,8 +144,6 @@ public: GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, int p_params_count); GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace); - void *get_method_thunk(const StringName &p_name, int p_params_count = 0); - GDMonoField *get_field(const StringName &p_name); const Vector<GDMonoField *> &get_all_fields(); diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 7b8e6f89e9..d84359b1ab 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -32,8 +32,10 @@ #include <mono/metadata/attrdefs.h> +#include "gd_mono_cache.h" #include "gd_mono_class.h" #include "gd_mono_marshal.h" +#include "gd_mono_utils.h" void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) { mono_field_set_value(p_object, mono_field, &p_ptr); @@ -337,7 +339,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ } if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - if (GDMonoUtils::tools_godot_api_check()) { + if (GDMonoCache::tools_godot_api_check()) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); mono_field_set_value(p_object, mono_field, managed); break; @@ -491,7 +493,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ } if (type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - if (GDMonoUtils::tools_godot_api_check()) { + if (GDMonoCache::tools_godot_api_check()) { MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array)); mono_field_set_value(p_object, mono_field, managed); break; diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h index d7962eac8b..173e1613bf 100644 --- a/modules/mono/mono_gd/gd_mono_header.h +++ b/modules/mono/mono_gd/gd_mono_header.h @@ -33,6 +33,12 @@ #include "core/int_types.h" +#ifdef WIN32 +#define GD_MONO_STDCALL __stdcall +#else +#define GD_MONO_STDCALL +#endif + class GDMonoAssembly; class GDMonoClass; class GDMonoField; diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index 7b3421fdb3..261b800619 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -30,7 +30,6 @@ #include "gd_mono_log.h" -#include <mono/utils/mono-logger.h> #include <stdlib.h> // abort #include "core/os/dir_access.h" @@ -39,7 +38,19 @@ #include "../godotsharp_dirs.h" #include "../utils/string_utils.h" -static int log_level_get_id(const char *p_log_level) { +static CharString get_default_log_level() { +#ifdef DEBUG_ENABLED + return String("info").utf8(); +#else + return String("warning").utf8(); +#endif +} + +GDMonoLog *GDMonoLog::singleton = NULL; + +#if !defined(JAVASCRIPT_ENABLED) + +static int get_log_level_id(const char *p_log_level) { const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", NULL }; @@ -53,11 +64,11 @@ static int log_level_get_id(const char *p_log_level) { return -1; } -static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data) { +void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) { - FileAccess *f = GDMonoLog::get_singleton()->get_log_file(); + FileAccess *f = GDMonoLog::get_singleton()->log_file; - if (GDMonoLog::get_singleton()->get_log_level_id() >= log_level_get_id(log_level)) { + if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) { String text(message); text += " (in domain "; text += log_domain; @@ -72,7 +83,7 @@ static void mono_log_callback(const char *log_domain, const char *log_level, con } if (fatal) { - ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: '" + GDMonoLog::get_singleton()->get_log_file_path() + "'."); + ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'."); // Make sure to flush before aborting f->flush(); f->close(); @@ -82,8 +93,6 @@ static void mono_log_callback(const char *log_domain, const char *log_level, con } } -GDMonoLog *GDMonoLog::singleton = NULL; - bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { if (!DirAccess::exists(p_logs_dir)) { @@ -129,17 +138,13 @@ void GDMonoLog::initialize() { CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8(); - if (log_level.length() != 0 && log_level_get_id(log_level.get_data()) == -1) { + if (log_level.length() != 0 && get_log_level_id(log_level.get_data()) == -1) { ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'."); log_level = CharString(); } if (log_level.length() == 0) { -#ifdef DEBUG_ENABLED - log_level = String("info").utf8(); -#else - log_level = String("warning").utf8(); -#endif + log_level = get_default_log_level(); } String logs_dir = GodotSharpDirs::get_mono_logs_dir(); @@ -149,11 +154,14 @@ void GDMonoLog::initialize() { OS::Date date_now = OS::get_singleton()->get_date(); OS::Time time_now = OS::get_singleton()->get_time(); - int pid = OS::get_singleton()->get_process_id(); - String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt", + String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d", date_now.year, date_now.month, date_now.day, - time_now.hour, time_now.min, time_now.sec, pid); + time_now.hour, time_now.min, time_now.sec); + + log_file_name += str_format(" (%d)", OS::get_singleton()->get_process_id()); + + log_file_name += ".txt"; log_file_path = logs_dir.plus_file(log_file_name); @@ -164,7 +172,7 @@ void GDMonoLog::initialize() { } mono_trace_set_level_string(log_level.get_data()); - log_level_id = log_level_get_id(log_level.get_data()); + log_level_id = get_log_level_id(log_level.get_data()); if (log_file) { OS::get_singleton()->print("Mono: Logfile is: %s\n", log_file_path.utf8().get_data()); @@ -190,3 +198,22 @@ GDMonoLog::~GDMonoLog() { memdelete(log_file); } } + +#else + +void GDMonoLog::initialize() { + CharString log_level = get_default_log_level(); + mono_trace_set_level_string(log_level.get_data()); +} + +GDMonoLog::GDMonoLog() { + + singleton = this; +} + +GDMonoLog::~GDMonoLog() { + + singleton = NULL; +} + +#endif // !defined(JAVASCRIPT_ENABLED) diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index 91d0557aa3..4cd5a662fb 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -31,10 +31,17 @@ #ifndef GD_MONO_LOG_H #define GD_MONO_LOG_H +#include <mono/utils/mono-logger.h> + +#include "core/typedefs.h" + +#if !defined(JAVASCRIPT_ENABLED) #include "core/os/file_access.h" +#endif class GDMonoLog { +#if !defined(JAVASCRIPT_ENABLED) int log_level_id; FileAccess *log_file; @@ -43,6 +50,9 @@ class GDMonoLog { bool _try_create_logs_dir(const String &p_logs_dir); void _delete_old_log_files(const String &p_logs_dir); + static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data); +#endif + static GDMonoLog *singleton; public: @@ -50,10 +60,6 @@ public: void initialize(); - _FORCE_INLINE_ FileAccess *get_log_file() { return log_file; } - _FORCE_INLINE_ String get_log_file_path() { return log_file_path; } - _FORCE_INLINE_ int get_log_level_id() { return log_level_id; } - GDMonoLog(); ~GDMonoLog(); }; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 7aac691102..3827960e6b 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -31,6 +31,7 @@ #include "gd_mono_marshal.h" #include "gd_mono.h" +#include "gd_mono_cache.h" #include "gd_mono_class.h" namespace GDMonoMarshal { @@ -556,7 +557,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty } if (type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - if (GDMonoUtils::tools_godot_api_check()) { + if (GDMonoCache::tools_godot_api_check()) { return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } else { return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array()); @@ -683,7 +684,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty } if (p_type.type_class->implements_interface(CACHED_CLASS(System_Collections_IEnumerable))) { - if (GDMonoUtils::tools_godot_api_check()) { + if (GDMonoCache::tools_godot_api_check()) { return GDMonoUtils::create_managed_from(p_var->operator Array(), CACHED_CLASS(Array)); } else { return (MonoObject *)GDMonoMarshal::Array_to_mono_array(p_var->operator Array()); @@ -834,14 +835,14 @@ Variant mono_object_to_variant(MonoObject *p_obj) { if (CACHED_CLASS(Array) == type_class) { MonoException *exc = NULL; - Array *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Array, GetPtr), p_obj, &exc); + Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc); UNHANDLED_EXCEPTION(exc); return ptr ? Variant(*ptr) : Variant(); } if (CACHED_CLASS(Dictionary) == type_class) { MonoException *exc = NULL; - Dictionary *ptr = invoke_method_thunk(CACHED_METHOD_THUNK(Dictionary, GetPtr), p_obj, &exc); + Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc); UNHANDLED_EXCEPTION(exc); return ptr ? Variant(*ptr) : Variant(); } diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 3fa958ac32..53eae45320 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -43,6 +43,11 @@ T unbox(MonoObject *p_obj) { return *(T *)mono_object_unbox(p_obj); } +template <typename T> +T *unbox_addr(MonoObject *p_obj) { + return (T *)mono_object_unbox(p_obj); +} + #define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x) #define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x) #define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x) diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp index 968b316a3e..080b3a676a 100644 --- a/modules/mono/mono_gd/gd_mono_method.cpp +++ b/modules/mono/mono_gd/gd_mono_method.cpp @@ -30,8 +30,10 @@ #include "gd_mono_method.h" +#include "gd_mono_cache.h" #include "gd_mono_class.h" #include "gd_mono_marshal.h" +#include "gd_mono_utils.h" #include <mono/metadata/attrdefs.h> @@ -99,10 +101,6 @@ IMonoClassMember::Visibility GDMonoMethod::get_visibility() { } } -void *GDMonoMethod::get_thunk() { - return mono_method_get_unmanaged_thunk(mono_method); -} - MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) { if (get_return_type().type_encoding != MONO_TYPE_VOID || get_parameters_count() > 0) { MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), get_parameters_count()); diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h index 2fc8628f27..abbae92e29 100644 --- a/modules/mono/mono_gd/gd_mono_method.h +++ b/modules/mono/mono_gd/gd_mono_method.h @@ -71,11 +71,11 @@ public: virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) GD_FINAL; void fetch_attributes(); + _FORCE_INLINE_ MonoMethod *get_mono_ptr() { return mono_method; } + _FORCE_INLINE_ int get_parameters_count() { return params_count; } _FORCE_INLINE_ ManagedType get_return_type() { return return_type; } - void *get_thunk(); - MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = NULL); MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = NULL); MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = NULL); diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h new file mode 100644 index 0000000000..9fe9e724f2 --- /dev/null +++ b/modules/mono/mono_gd/gd_mono_method_thunk.h @@ -0,0 +1,302 @@ +#ifndef GD_MONO_METHOD_THUNK_H +#define GD_MONO_METHOD_THUNK_H + +#include <type_traits> + +#include "gd_mono_class.h" +#include "gd_mono_header.h" +#include "gd_mono_marshal.h" +#include "gd_mono_method.h" +#include "gd_mono_utils.h" + +#if !defined(JAVASCRIPT_ENABLED) +#define HAVE_METHOD_THUNKS +#endif + +#ifdef HAVE_METHOD_THUNKS + +template <class... ParamTypes> +struct GDMonoMethodThunk { + + typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **); + + M mono_method_thunk; + +public: + _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) { + GD_MONO_BEGIN_RUNTIME_INVOKE; + mono_method_thunk(p_args..., r_exc); + GD_MONO_END_RUNTIME_INVOKE; + } + + _FORCE_INLINE_ bool is_null() { + return mono_method_thunk == NULL; + } + + _FORCE_INLINE_ void nullify() { + mono_method_thunk = NULL; + } + + _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { +#ifdef DEBUG_ENABLED + CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); + + if (p_mono_method->is_static()) { + CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); + } else { + CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); + } +#endif + mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); + } + + GDMonoMethodThunk() : + mono_method_thunk(NULL) { + } + + explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { + set_from_method(p_mono_method); + } +}; + +template <class R, class... ParamTypes> +struct GDMonoMethodThunkR { + + typedef R(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **); + + M mono_method_thunk; + +public: + _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) { + GD_MONO_BEGIN_RUNTIME_INVOKE; + R r = mono_method_thunk(p_args..., r_exc); + GD_MONO_END_RUNTIME_INVOKE; + return r; + } + + _FORCE_INLINE_ bool is_null() { + return mono_method_thunk == NULL; + } + + _FORCE_INLINE_ void nullify() { + mono_method_thunk = NULL; + } + + _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { +#ifdef DEBUG_ENABLED + CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); + + if (p_mono_method->is_static()) { + CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); + } else { + CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); + } +#endif + mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); + } + + GDMonoMethodThunkR() : + mono_method_thunk(NULL) { + } + + explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { +#ifdef DEBUG_ENABLED + CRASH_COND(p_mono_method == NULL); +#endif + mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr()); + } +}; + +#else + +template <unsigned int ThunkParamCount, class P1, class... ParamTypes> +struct VariadicInvokeMonoMethodImpl { + static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { + if (p_mono_method->is_static()) { + void *args[ThunkParamCount] = { p_arg1, p_args... }; + p_mono_method->invoke_raw(NULL, args, r_exc); + } else { + void *args[ThunkParamCount] = { p_args... }; + p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); + } + } +}; + +template <unsigned int ThunkParamCount, class... ParamTypes> +struct VariadicInvokeMonoMethod { + static void invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) { + VariadicInvokeMonoMethodImpl<ThunkParamCount, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc); + } +}; + +template <> +struct VariadicInvokeMonoMethod<0> { + static void invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) { +#ifdef DEBUG_ENABLED + CRASH_COND(!p_mono_method->is_static()); +#endif + p_mono_method->invoke_raw(NULL, NULL, r_exc); + } +}; + +template <class P1> +struct VariadicInvokeMonoMethod<1, P1> { + static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { + if (p_mono_method->is_static()) { + void *args[1] = { p_arg1 }; + p_mono_method->invoke_raw(NULL, args, r_exc); + } else { + p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc); + } + } +}; + +template <class R> +R unbox_if_needed(MonoObject *p_val, const ManagedType &, typename std::enable_if<!std::is_pointer<R>::value>::type * = 0) { + return GDMonoMarshal::unbox<R>(p_val); +} + +template <class R> +R unbox_if_needed(MonoObject *p_val, const ManagedType &p_type, typename std::enable_if<std::is_pointer<R>::value>::type * = 0) { + if (mono_class_is_valuetype(p_type.type_class->get_mono_ptr())) { + return GDMonoMarshal::unbox<R>(p_val); + } else { + // If it's not a value type, we assume 'R' is a pointer to 'MonoObject' or a compatible type, like 'MonoException'. + return (R)p_val; + } +} + +template <unsigned int ThunkParamCount, class R, class P1, class... ParamTypes> +struct VariadicInvokeMonoMethodRImpl { + static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) { + if (p_mono_method->is_static()) { + void *args[ThunkParamCount] = { p_arg1, p_args... }; + MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc); + return unbox_if_needed<R>(r, p_mono_method->get_return_type()); + } else { + void *args[ThunkParamCount] = { p_args... }; + MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc); + return unbox_if_needed<R>(r, p_mono_method->get_return_type()); + } + } +}; + +template <unsigned int ThunkParamCount, class R, class... ParamTypes> +struct VariadicInvokeMonoMethodR { + static R invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) { + return VariadicInvokeMonoMethodRImpl<ThunkParamCount, R, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc); + } +}; + +template <class R> +struct VariadicInvokeMonoMethodR<0, R> { + static R invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) { +#ifdef DEBUG_ENABLED + CRASH_COND(!p_mono_method->is_static()); +#endif + MonoObject *r = p_mono_method->invoke_raw(NULL, NULL, r_exc); + return unbox_if_needed<R>(r, p_mono_method->get_return_type()); + } +}; + +template <class R, class P1> +struct VariadicInvokeMonoMethodR<1, R, P1> { + static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) { + if (p_mono_method->is_static()) { + void *args[1] = { p_arg1 }; + MonoObject *r = p_mono_method->invoke_raw(NULL, args, r_exc); + return unbox_if_needed<R>(r, p_mono_method->get_return_type()); + } else { + MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, NULL, r_exc); + return unbox_if_needed<R>(r, p_mono_method->get_return_type()); + } + } +}; + +template <class... ParamTypes> +struct GDMonoMethodThunk { + + GDMonoMethod *mono_method; + +public: + _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) { + VariadicInvokeMonoMethod<sizeof...(ParamTypes), ParamTypes...>::invoke(mono_method, p_args..., r_exc); + } + + _FORCE_INLINE_ bool is_null() { + return mono_method == NULL; + } + + _FORCE_INLINE_ void nullify() { + mono_method = NULL; + } + + _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { +#ifdef DEBUG_ENABLED + CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID); + + if (p_mono_method->is_static()) { + CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); + } else { + CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); + } +#endif + mono_method = p_mono_method; + } + + GDMonoMethodThunk() : + mono_method(NULL) { + } + + explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) { + set_from_method(p_mono_method); + } +}; + +template <class R, class... ParamTypes> +struct GDMonoMethodThunkR { + + GDMonoMethod *mono_method; + +public: + _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) { + return VariadicInvokeMonoMethodR<sizeof...(ParamTypes), R, ParamTypes...>::invoke(mono_method, p_args..., r_exc); + } + + _FORCE_INLINE_ bool is_null() { + return mono_method == NULL; + } + + _FORCE_INLINE_ void nullify() { + mono_method = NULL; + } + + _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) { +#ifdef DEBUG_ENABLED + CRASH_COND(p_mono_method == NULL); + CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID); + + if (p_mono_method->is_static()) { + CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes)); + } else { + CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1)); + } +#endif + mono_method = p_mono_method; + } + + GDMonoMethodThunkR() : + mono_method(NULL) { + } + + explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) { + set_from_method(p_mono_method); + } +}; + +#endif + +#endif // GD_MONO_METHOD_THUNK_H diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp index f1da00638f..277fe10087 100644 --- a/modules/mono/mono_gd/gd_mono_property.cpp +++ b/modules/mono/mono_gd/gd_mono_property.cpp @@ -30,8 +30,10 @@ #include "gd_mono_property.h" +#include "gd_mono_cache.h" #include "gd_mono_class.h" #include "gd_mono_marshal.h" +#include "gd_mono_utils.h" #include <mono/metadata/attrdefs.h> diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 6504fbe423..8d7aaa97f2 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -45,273 +45,13 @@ #include "../utils/macros.h" #include "../utils/mutex_utils.h" #include "gd_mono.h" +#include "gd_mono_cache.h" #include "gd_mono_class.h" #include "gd_mono_marshal.h" +#include "gd_mono_method_thunk.h" namespace GDMonoUtils { -MonoCache mono_cache; - -#define CACHE_AND_CHECK(m_var, m_val) \ - { \ - CRASH_COND(m_var != NULL); \ - m_var = m_val; \ - ERR_FAIL_COND_MSG(!m_var, "Mono Cache: Member " #m_var " is null."); \ - } - -#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val) -#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_ns##_##m_class, m_val) -#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.rawclass_##m_class, m_val) -#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.field_##m_class##_##m_field, m_val) -#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.method_##m_class##_##m_method, m_val) -#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val) -#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val) - -void MonoCache::clear_corlib_cache() { - - corlib_cache_updated = false; - - class_MonoObject = NULL; - class_bool = NULL; - class_int8_t = NULL; - class_int16_t = NULL; - class_int32_t = NULL; - class_int64_t = NULL; - class_uint8_t = NULL; - class_uint16_t = NULL; - class_uint32_t = NULL; - class_uint64_t = NULL; - class_float = NULL; - class_double = NULL; - class_String = NULL; - class_IntPtr = NULL; - - class_System_Collections_IEnumerable = NULL; - class_System_Collections_IDictionary = NULL; - -#ifdef DEBUG_ENABLED - class_System_Diagnostics_StackTrace = NULL; - methodthunk_System_Diagnostics_StackTrace_GetFrames = NULL; - method_System_Diagnostics_StackTrace_ctor_bool = NULL; - method_System_Diagnostics_StackTrace_ctor_Exception_bool = NULL; -#endif - - class_KeyNotFoundException = NULL; -} - -void MonoCache::clear_godot_api_cache() { - - godot_api_cache_updated = false; - - rawclass_Dictionary = NULL; - - class_Vector2 = NULL; - class_Rect2 = NULL; - class_Transform2D = NULL; - class_Vector3 = NULL; - class_Basis = NULL; - class_Quat = NULL; - class_Transform = NULL; - class_AABB = NULL; - class_Color = NULL; - class_Plane = NULL; - class_NodePath = NULL; - class_RID = NULL; - class_GodotObject = NULL; - class_GodotResource = NULL; - class_Node = NULL; - class_Control = NULL; - class_Spatial = NULL; - class_WeakRef = NULL; - class_Array = NULL; - class_Dictionary = NULL; - class_MarshalUtils = NULL; - class_ISerializationListener = NULL; - -#ifdef DEBUG_ENABLED - class_DebuggingUtils = NULL; - methodthunk_DebuggingUtils_GetStackFrameInfo = NULL; -#endif - - class_ExportAttribute = NULL; - field_ExportAttribute_hint = NULL; - field_ExportAttribute_hintString = NULL; - class_SignalAttribute = NULL; - class_ToolAttribute = NULL; - class_RemoteAttribute = NULL; - class_SyncAttribute = NULL; - class_MasterAttribute = NULL; - class_PuppetAttribute = NULL; - class_SlaveAttribute = NULL; - class_RemoteSyncAttribute = NULL; - class_MasterSyncAttribute = NULL; - class_PuppetSyncAttribute = NULL; - class_GodotMethodAttribute = NULL; - field_GodotMethodAttribute_methodName = NULL; - - field_GodotObject_ptr = NULL; - field_NodePath_ptr = NULL; - field_Image_ptr = NULL; - field_RID_ptr = NULL; - - methodthunk_GodotObject_Dispose = NULL; - methodthunk_Array_GetPtr = NULL; - methodthunk_Dictionary_GetPtr = NULL; - methodthunk_SignalAwaiter_SignalCallback = NULL; - methodthunk_SignalAwaiter_FailureCallback = NULL; - methodthunk_GodotTaskScheduler_Activate = NULL; - - // Start of MarshalUtils methods - - methodthunk_MarshalUtils_TypeIsGenericArray = NULL; - methodthunk_MarshalUtils_TypeIsGenericDictionary = NULL; - - methodthunk_MarshalUtils_ArrayGetElementType = NULL; - methodthunk_MarshalUtils_DictionaryGetKeyValueTypes = NULL; - - methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType = NULL; - methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType = NULL; - methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info = NULL; - methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info = NULL; - - methodthunk_MarshalUtils_MakeGenericArrayType = NULL; - methodthunk_MarshalUtils_MakeGenericDictionaryType = NULL; - - methodthunk_MarshalUtils_EnumerableToArray = NULL; - methodthunk_MarshalUtils_IDictionaryToDictionary = NULL; - methodthunk_MarshalUtils_GenericIDictionaryToDictionary = NULL; - - // End of MarshalUtils methods - - task_scheduler_handle = Ref<MonoGCHandle>(); -} - -#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class)) -#define GODOT_API_NS_CLAS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class)) - -void update_corlib_cache() { - - CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class())); - CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class())); - CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class())); - CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class())); - CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class())); - CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class())); - CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class())); - CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class())); - CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class())); - CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class())); - CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class())); - CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class())); - CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class())); - CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class())); - - CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable")); - CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary")); - -#ifdef DEBUG_ENABLED - CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace")); - CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, (StackTrace_GetFrames)CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_thunk("GetFrames")); - CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true)); - CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true)); -#endif - - CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException")); - - mono_cache.corlib_cache_updated = true; -} - -void update_godot_api_cache() { - - CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2)); - CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2)); - CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D)); - CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3)); - CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis)); - CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat)); - CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform)); - CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB)); - CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color)); - CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane)); - CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath)); - CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID)); - CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object)); - CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource)); - CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node)); - CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control)); - CACHE_CLASS_AND_CHECK(Spatial, GODOT_API_CLASS(Spatial)); - CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef)); - CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)); - CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)); - CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils)); - CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener)); - -#ifdef DEBUG_ENABLED - CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils)); -#endif - - // Attributes - CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute)); - CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint")); - CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString")); - CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute)); - CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute)); - CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute)); - CACHE_CLASS_AND_CHECK(SyncAttribute, GODOT_API_CLASS(SyncAttribute)); - CACHE_CLASS_AND_CHECK(MasterAttribute, GODOT_API_CLASS(MasterAttribute)); - CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute)); - CACHE_CLASS_AND_CHECK(SlaveAttribute, GODOT_API_CLASS(SlaveAttribute)); - CACHE_CLASS_AND_CHECK(RemoteSyncAttribute, GODOT_API_CLASS(RemoteSyncAttribute)); - CACHE_CLASS_AND_CHECK(MasterSyncAttribute, GODOT_API_CLASS(MasterSyncAttribute)); - CACHE_CLASS_AND_CHECK(PuppetSyncAttribute, GODOT_API_CLASS(PuppetSyncAttribute)); - CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute)); - CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName")); - - CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD)); - CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD)); - CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD)); - - CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, (GodotObject_Dispose)CACHED_CLASS(GodotObject)->get_method_thunk("Dispose", 0)); - CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, (Array_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method_thunk("GetPtr", 0)); - CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, (Dictionary_GetPtr)GODOT_API_NS_CLAS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method_thunk("GetPtr", 0)); - CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, (SignalAwaiter_SignalCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("SignalCallback", 1)); - CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, FailureCallback, (SignalAwaiter_FailureCallback)GODOT_API_CLASS(SignalAwaiter)->get_method_thunk("FailureCallback", 0)); - CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, (GodotTaskScheduler_Activate)GODOT_API_CLASS(GodotTaskScheduler)->get_method_thunk("Activate", 0)); - - // Start of MarshalUtils methods - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, (TypeIsGenericArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericArray", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, (TypeIsGenericDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("TypeIsGenericDictionary", 1)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, (GenericIDictionaryIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2)); - - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, EnumerableToArray, (EnumerableToArray)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("EnumerableToArray", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, IDictionaryToDictionary, (IDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("IDictionaryToDictionary", 2)); - CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryToDictionary, (GenericIDictionaryToDictionary)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryToDictionary", 2)); - - // End of MarshalUtils methods - -#ifdef DEBUG_ENABLED - CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, (DebugUtils_StackFrameInfo)GODOT_API_CLASS(DebuggingUtils)->get_method_thunk("GetStackFrameInfo", 4)); -#endif - - // TODO Move to CSharpLanguage::init() and do handle disposal - MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr()); - GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler)); - mono_cache.task_scheduler_handle = MonoGCHandle::create_strong(task_scheduler); - - mono_cache.godot_api_cache_updated = true; -} - MonoObject *unmanaged_get_managed(Object *unmanaged) { if (!unmanaged) @@ -386,7 +126,7 @@ void set_main_thread(MonoThread *p_thread) { void attach_current_thread() { ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized()); - MonoThread *mono_thread = mono_thread_attach(mono_domain_get()); + MonoThread *mono_thread = mono_thread_attach(mono_get_root_domain()); ERR_FAIL_NULL(mono_thread); } @@ -421,7 +161,7 @@ GDMonoClass *type_get_proxy_class(const StringName &p_type) { if (klass && klass->is_static()) { // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object. - return mono_cache.class_GodotObject; + return GDMonoCache::cached_data.class_GodotObject; } #ifdef TOOLS_ENABLED @@ -751,16 +491,16 @@ uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool & } void dispose(MonoObject *p_mono_object, MonoException **r_exc) { - invoke_method_thunk(CACHED_METHOD_THUNK(GodotObject, Dispose), p_mono_object, r_exc); + CACHED_METHOD_THUNK(GodotObject, Dispose).invoke(p_mono_object, r_exc); } namespace Marshal { #ifdef MONO_GLUE_ENABLED #ifdef TOOLS_ENABLED -#define NO_GLUE_RET(m_ret) \ - { \ - if (!mono_cache.godot_api_cache_updated) return m_ret; \ +#define NO_GLUE_RET(m_ret) \ + { \ + if (!GDMonoCache::cached_data.godot_api_cache_updated) return m_ret; \ } #else #define NO_GLUE_RET(m_ret) \ @@ -773,68 +513,60 @@ namespace Marshal { bool type_is_generic_array(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - TypeIsGenericArray thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray); MonoException *exc = NULL; - MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } bool type_is_generic_dictionary(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - TypeIsGenericDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary); MonoException *exc = NULL; - MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) { - ArrayGetElementType thunk = CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType); MonoException *exc = NULL; - invoke_method_thunk(thunk, p_array_reftype, r_elem_reftype, &exc); + CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc); UNHANDLED_EXCEPTION(exc); } void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { - DictionaryGetKeyValueTypes thunk = CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes); MonoException *exc = NULL; - invoke_method_thunk(thunk, p_dict_reftype, r_key_reftype, r_value_reftype, &exc); + CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc); UNHANDLED_EXCEPTION(exc); } bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - GenericIEnumerableIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType); MonoException *exc = NULL; - MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype) { NO_GLUE_RET(false); - GenericIDictionaryIsAssignableFromType thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType); MonoException *exc = NULL; - MonoBoolean res = invoke_method_thunk(thunk, p_reftype, &exc); + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType).invoke(p_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } bool generic_ienumerable_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_elem_reftype) { NO_GLUE_RET(false); - GenericIEnumerableIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info); MonoException *exc = NULL; - MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_elem_reftype, &exc); + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info).invoke(p_reftype, r_elem_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) { NO_GLUE_RET(false); - GenericIDictionaryIsAssignableFromType_with_info thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info); MonoException *exc = NULL; - MonoBoolean res = invoke_method_thunk(thunk, p_reftype, r_key_reftype, r_value_reftype, &exc); + MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info).invoke(p_reftype, r_key_reftype, r_value_reftype, &exc); UNHANDLED_EXCEPTION(exc); return (bool)res; } @@ -842,9 +574,8 @@ bool generic_idictionary_is_assignable_from(MonoReflectionType *p_reftype, MonoR Array enumerable_to_array(MonoObject *p_enumerable) { NO_GLUE_RET(Array()); Array result; - EnumerableToArray thunk = CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray); MonoException *exc = NULL; - invoke_method_thunk(thunk, p_enumerable, &result, &exc); + CACHED_METHOD_THUNK(MarshalUtils, EnumerableToArray).invoke(p_enumerable, &result, &exc); UNHANDLED_EXCEPTION(exc); return result; } @@ -852,9 +583,8 @@ Array enumerable_to_array(MonoObject *p_enumerable) { Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) { NO_GLUE_RET(Dictionary()); Dictionary result; - IDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary); MonoException *exc = NULL; - invoke_method_thunk(thunk, p_idictionary, &result, &exc); + CACHED_METHOD_THUNK(MarshalUtils, IDictionaryToDictionary).invoke(p_idictionary, &result, &exc); UNHANDLED_EXCEPTION(exc); return result; } @@ -862,27 +592,24 @@ Dictionary idictionary_to_dictionary(MonoObject *p_idictionary) { Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary) { NO_GLUE_RET(Dictionary()); Dictionary result; - GenericIDictionaryToDictionary thunk = CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary); MonoException *exc = NULL; - invoke_method_thunk(thunk, p_generic_idictionary, &result, &exc); + CACHED_METHOD_THUNK(MarshalUtils, GenericIDictionaryToDictionary).invoke(p_generic_idictionary, &result, &exc); UNHANDLED_EXCEPTION(exc); return result; } GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) { NO_GLUE_RET(NULL); - MakeGenericArrayType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType); MonoException *exc = NULL; - MonoReflectionType *reftype = invoke_method_thunk(thunk, p_elem_reftype, &exc); + MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc); UNHANDLED_EXCEPTION(exc); return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); } GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) { NO_GLUE_RET(NULL); - MakeGenericDictionaryType thunk = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType); MonoException *exc = NULL; - MonoReflectionType *reftype = invoke_method_thunk(thunk, p_key_reftype, p_value_reftype, &exc); + MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc); UNHANDLED_EXCEPTION(exc); return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype))); } diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index d73743bf0b..848df843fe 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -49,33 +49,6 @@ namespace GDMonoUtils { -typedef void (*GodotObject_Dispose)(MonoObject *, MonoException **); -typedef Array *(*Array_GetPtr)(MonoObject *, MonoException **); -typedef Dictionary *(*Dictionary_GetPtr)(MonoObject *, MonoException **); -typedef MonoObject *(*SignalAwaiter_SignalCallback)(MonoObject *, MonoArray *, MonoException **); -typedef MonoObject *(*SignalAwaiter_FailureCallback)(MonoObject *, MonoException **); -typedef MonoObject *(*GodotTaskScheduler_Activate)(MonoObject *, MonoException **); -typedef MonoArray *(*StackTrace_GetFrames)(MonoObject *, MonoException **); -typedef void (*DebugUtils_StackFrameInfo)(MonoObject *, MonoString **, int *, MonoString **, MonoException **); - -typedef MonoBoolean (*TypeIsGenericArray)(MonoReflectionType *, MonoException **); -typedef MonoBoolean (*TypeIsGenericDictionary)(MonoReflectionType *, MonoException **); - -typedef void (*ArrayGetElementType)(MonoReflectionType *, MonoReflectionType **, MonoException **); -typedef void (*DictionaryGetKeyValueTypes)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); - -typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType)(MonoReflectionType *, MonoException **); -typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType)(MonoReflectionType *, MonoException **); -typedef MonoBoolean (*GenericIEnumerableIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoException **); -typedef MonoBoolean (*GenericIDictionaryIsAssignableFromType_with_info)(MonoReflectionType *, MonoReflectionType **, MonoReflectionType **, MonoException **); - -typedef MonoReflectionType *(*MakeGenericArrayType)(MonoReflectionType *, MonoException **); -typedef MonoReflectionType *(*MakeGenericDictionaryType)(MonoReflectionType *, MonoReflectionType *, MonoException **); - -typedef void (*EnumerableToArray)(MonoObject *, Array *, MonoException **); -typedef void (*IDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **); -typedef void (*GenericIDictionaryToDictionary)(MonoObject *, Dictionary *, MonoException **); - namespace Marshal { bool type_is_generic_array(MonoReflectionType *p_reftype); @@ -98,157 +71,6 @@ Dictionary generic_idictionary_to_dictionary(MonoObject *p_generic_idictionary); } // namespace Marshal -// End of MarshalUtils methods - -struct MonoCache { - - // ----------------------------------------------- - // corlib classes - - // Let's use the no-namespace format for these too - GDMonoClass *class_MonoObject; - GDMonoClass *class_bool; - GDMonoClass *class_int8_t; - GDMonoClass *class_int16_t; - GDMonoClass *class_int32_t; - GDMonoClass *class_int64_t; - GDMonoClass *class_uint8_t; - GDMonoClass *class_uint16_t; - GDMonoClass *class_uint32_t; - GDMonoClass *class_uint64_t; - GDMonoClass *class_float; - GDMonoClass *class_double; - GDMonoClass *class_String; - GDMonoClass *class_IntPtr; - - GDMonoClass *class_System_Collections_IEnumerable; - GDMonoClass *class_System_Collections_IDictionary; - -#ifdef DEBUG_ENABLED - GDMonoClass *class_System_Diagnostics_StackTrace; - StackTrace_GetFrames methodthunk_System_Diagnostics_StackTrace_GetFrames; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool; - GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool; -#endif - - GDMonoClass *class_KeyNotFoundException; - - MonoClass *rawclass_Dictionary; - // ----------------------------------------------- - - GDMonoClass *class_Vector2; - GDMonoClass *class_Rect2; - GDMonoClass *class_Transform2D; - GDMonoClass *class_Vector3; - GDMonoClass *class_Basis; - GDMonoClass *class_Quat; - GDMonoClass *class_Transform; - GDMonoClass *class_AABB; - GDMonoClass *class_Color; - GDMonoClass *class_Plane; - GDMonoClass *class_NodePath; - GDMonoClass *class_RID; - GDMonoClass *class_GodotObject; - GDMonoClass *class_GodotResource; - GDMonoClass *class_Node; - GDMonoClass *class_Control; - GDMonoClass *class_Spatial; - GDMonoClass *class_WeakRef; - GDMonoClass *class_Array; - GDMonoClass *class_Dictionary; - GDMonoClass *class_MarshalUtils; - GDMonoClass *class_ISerializationListener; - -#ifdef DEBUG_ENABLED - GDMonoClass *class_DebuggingUtils; - DebugUtils_StackFrameInfo methodthunk_DebuggingUtils_GetStackFrameInfo; -#endif - - GDMonoClass *class_ExportAttribute; - GDMonoField *field_ExportAttribute_hint; - GDMonoField *field_ExportAttribute_hintString; - GDMonoClass *class_SignalAttribute; - GDMonoClass *class_ToolAttribute; - GDMonoClass *class_RemoteAttribute; - GDMonoClass *class_SyncAttribute; - GDMonoClass *class_RemoteSyncAttribute; - GDMonoClass *class_MasterSyncAttribute; - GDMonoClass *class_PuppetSyncAttribute; - GDMonoClass *class_MasterAttribute; - GDMonoClass *class_PuppetAttribute; - GDMonoClass *class_SlaveAttribute; - GDMonoClass *class_GodotMethodAttribute; - GDMonoField *field_GodotMethodAttribute_methodName; - - GDMonoField *field_GodotObject_ptr; - GDMonoField *field_NodePath_ptr; - GDMonoField *field_Image_ptr; - GDMonoField *field_RID_ptr; - - GodotObject_Dispose methodthunk_GodotObject_Dispose; - Array_GetPtr methodthunk_Array_GetPtr; - Dictionary_GetPtr methodthunk_Dictionary_GetPtr; - SignalAwaiter_SignalCallback methodthunk_SignalAwaiter_SignalCallback; - SignalAwaiter_FailureCallback methodthunk_SignalAwaiter_FailureCallback; - GodotTaskScheduler_Activate methodthunk_GodotTaskScheduler_Activate; - - // Start of MarshalUtils methods - - TypeIsGenericArray methodthunk_MarshalUtils_TypeIsGenericArray; - TypeIsGenericDictionary methodthunk_MarshalUtils_TypeIsGenericDictionary; - - ArrayGetElementType methodthunk_MarshalUtils_ArrayGetElementType; - DictionaryGetKeyValueTypes methodthunk_MarshalUtils_DictionaryGetKeyValueTypes; - - GenericIEnumerableIsAssignableFromType methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType; - GenericIDictionaryIsAssignableFromType methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType; - GenericIEnumerableIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIEnumerableIsAssignableFromType_with_info; - GenericIDictionaryIsAssignableFromType_with_info methodthunk_MarshalUtils_GenericIDictionaryIsAssignableFromType_with_info; - - MakeGenericArrayType methodthunk_MarshalUtils_MakeGenericArrayType; - MakeGenericDictionaryType methodthunk_MarshalUtils_MakeGenericDictionaryType; - - EnumerableToArray methodthunk_MarshalUtils_EnumerableToArray; - IDictionaryToDictionary methodthunk_MarshalUtils_IDictionaryToDictionary; - GenericIDictionaryToDictionary methodthunk_MarshalUtils_GenericIDictionaryToDictionary; - - // End of MarshalUtils methods - - Ref<MonoGCHandle> task_scheduler_handle; - - bool corlib_cache_updated; - bool godot_api_cache_updated; - - void clear_corlib_cache(); - void clear_godot_api_cache(); - - MonoCache() { - clear_corlib_cache(); - clear_godot_api_cache(); - } -}; - -extern MonoCache mono_cache; - -void update_corlib_cache(); -void update_godot_api_cache(); - -inline void clear_corlib_cache() { - mono_cache.clear_corlib_cache(); -} - -inline void clear_godot_api_cache() { - mono_cache.clear_godot_api_cache(); -} - -_FORCE_INLINE_ bool tools_godot_api_check() { -#ifdef TOOLS_ENABLED - return mono_cache.godot_api_cache_updated; -#else - return true; // Assume it's updated if this was called, otherwise it's a bug -#endif -} - _FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) { p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2); } @@ -324,20 +146,6 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc); #define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoMarshal::mono_string_to_godot((MonoString *)m_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(NULL))) -#define CACHED_CLASS(m_class) (GDMonoUtils::mono_cache.class_##m_class) -#define CACHED_CLASS_RAW(m_class) (GDMonoUtils::mono_cache.class_##m_class->get_mono_ptr()) -#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoUtils::mono_cache.rawclass_##m_class) -#define CACHED_FIELD(m_class, m_field) (GDMonoUtils::mono_cache.field_##m_class##_##m_field) -#define CACHED_METHOD(m_class, m_method) (GDMonoUtils::mono_cache.method_##m_class##_##m_method) -#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method) -#define CACHED_PROPERTY(m_class, m_property) (GDMonoUtils::mono_cache.property_##m_class##_##m_property) - -#ifdef REAL_T_IS_DOUBLE -#define REAL_T_MONOCLASS CACHED_CLASS_RAW(double) -#else -#define REAL_T_MONOCLASS CACHED_CLASS_RAW(float) -#endif - #define GD_MONO_BEGIN_RUNTIME_INVOKE \ int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \ _runtime_invoke_count_ref += 1; @@ -345,93 +153,4 @@ void dispose(MonoObject *p_mono_object, MonoException **r_exc); #define GD_MONO_END_RUNTIME_INVOKE \ _runtime_invoke_count_ref -= 1; -inline void invoke_method_thunk(void (*p_method_thunk)()) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - p_method_thunk(); - GD_MONO_END_RUNTIME_INVOKE; -} - -template <class R> -R invoke_method_thunk(R (*p_method_thunk)()) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = p_method_thunk(); - GD_MONO_END_RUNTIME_INVOKE; - return r; -} - -template <class P1> -void invoke_method_thunk(void (*p_method_thunk)(P1), P1 p_arg1) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - p_method_thunk(p_arg1); - GD_MONO_END_RUNTIME_INVOKE; -} - -template <class R, class P1> -R invoke_method_thunk(R (*p_method_thunk)(P1), P1 p_arg1) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = p_method_thunk(p_arg1); - GD_MONO_END_RUNTIME_INVOKE; - return r; -} - -template <class P1, class P2> -void invoke_method_thunk(void (*p_method_thunk)(P1, P2), P1 p_arg1, P2 p_arg2) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - p_method_thunk(p_arg1, p_arg2); - GD_MONO_END_RUNTIME_INVOKE; -} - -template <class R, class P1, class P2> -R invoke_method_thunk(R (*p_method_thunk)(P1, P2), P1 p_arg1, P2 p_arg2) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = p_method_thunk(p_arg1, p_arg2); - GD_MONO_END_RUNTIME_INVOKE; - return r; -} - -template <class P1, class P2, class P3> -void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3), P1 p_arg1, P2 p_arg2, P3 p_arg3) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - p_method_thunk(p_arg1, p_arg2, p_arg3); - GD_MONO_END_RUNTIME_INVOKE; -} - -template <class R, class P1, class P2, class P3> -R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3), P1 p_arg1, P2 p_arg2, P3 p_arg3) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = p_method_thunk(p_arg1, p_arg2, p_arg3); - GD_MONO_END_RUNTIME_INVOKE; - return r; -} - -template <class P1, class P2, class P3, class P4> -void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3, P4), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4); - GD_MONO_END_RUNTIME_INVOKE; -} - -template <class R, class P1, class P2, class P3, class P4> -R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3, P4), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4); - GD_MONO_END_RUNTIME_INVOKE; - return r; -} - -template <class P1, class P2, class P3, class P4, class P5> -void invoke_method_thunk(void (*p_method_thunk)(P1, P2, P3, P4, P5), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4, P5 p_arg5) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); - GD_MONO_END_RUNTIME_INVOKE; -} - -template <class R, class P1, class P2, class P3, class P4, class P5> -R invoke_method_thunk(R (*p_method_thunk)(P1, P2, P3, P4, P5), P1 p_arg1, P2 p_arg2, P3 p_arg3, P4 p_arg4, P5 p_arg5) { - GD_MONO_BEGIN_RUNTIME_INVOKE; - R r = p_method_thunk(p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); - GD_MONO_END_RUNTIME_INVOKE; - return r; -} - #endif // GD_MONOUTILS_H diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp index 189ceaab1b..ee16327856 100644 --- a/modules/mono/signal_awaiter_utils.cpp +++ b/modules/mono/signal_awaiter_utils.cpp @@ -31,6 +31,7 @@ #include "signal_awaiter_utils.h" #include "csharp_script.h" +#include "mono_gd/gd_mono_cache.h" #include "mono_gd/gd_mono_class.h" #include "mono_gd/gd_mono_marshal.h" #include "mono_gd/gd_mono_utils.h" @@ -98,7 +99,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc MonoException *exc = NULL; GD_MONO_BEGIN_RUNTIME_INVOKE; - invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback), get_target(), signal_args, &exc); + CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback).invoke(get_target(), signal_args, &exc); GD_MONO_END_RUNTIME_INVOKE; if (exc) { @@ -130,7 +131,7 @@ SignalAwaiterHandle::~SignalAwaiterHandle() { if (awaiter) { MonoException *exc = NULL; GD_MONO_BEGIN_RUNTIME_INVOKE; - invoke_method_thunk(CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback), awaiter, &exc); + CACHED_METHOD_THUNK(SignalAwaiter, FailureCallback).invoke(awaiter, &exc); GD_MONO_END_RUNTIME_INVOKE; if (exc) { diff --git a/modules/mono/utils/android_utils.cpp b/modules/mono/utils/android_utils.cpp deleted file mode 100644 index 7dd67e3b8e..0000000000 --- a/modules/mono/utils/android_utils.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/*************************************************************************/ -/* android_utils.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "android_utils.h" - -#ifdef __ANDROID__ - -#include "platform/android/thread_jandroid.h" - -namespace GDMonoUtils { -namespace Android { - -String get_app_native_lib_dir() { - JNIEnv *env = ThreadAndroid::get_env(); - - jclass activityThreadClass = env->FindClass("android/app/ActivityThread"); - jmethodID currentActivityThread = env->GetStaticMethodID(activityThreadClass, "currentActivityThread", "()Landroid/app/ActivityThread;"); - jobject activityThread = env->CallStaticObjectMethod(activityThreadClass, currentActivityThread); - jmethodID getApplication = env->GetMethodID(activityThreadClass, "getApplication", "()Landroid/app/Application;"); - jobject ctx = env->CallObjectMethod(activityThread, getApplication); - - jmethodID getApplicationInfo = env->GetMethodID(env->GetObjectClass(ctx), "getApplicationInfo", "()Landroid/content/pm/ApplicationInfo;"); - jobject applicationInfo = env->CallObjectMethod(ctx, getApplicationInfo); - jfieldID nativeLibraryDirField = env->GetFieldID(env->GetObjectClass(applicationInfo), "nativeLibraryDir", "Ljava/lang/String;"); - jstring nativeLibraryDir = (jstring)env->GetObjectField(applicationInfo, nativeLibraryDirField); - - String result; - - const char *const nativeLibraryDir_utf8 = env->GetStringUTFChars(nativeLibraryDir, NULL); - if (nativeLibraryDir_utf8) { - result.parse_utf8(nativeLibraryDir_utf8); - env->ReleaseStringUTFChars(nativeLibraryDir, nativeLibraryDir_utf8); - } - - return result; -} - -} // namespace Android -} // namespace GDMonoUtils - -#endif // __ANDROID__ diff --git a/modules/mono/utils/android_utils.h b/modules/mono/utils/android_utils.h deleted file mode 100644 index f911c3fdfe..0000000000 --- a/modules/mono/utils/android_utils.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* android_utils.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* 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 ANDROID_UTILS_H -#define ANDROID_UTILS_H - -#ifdef __ANDROID__ - -#include "core/ustring.h" - -namespace GDMonoUtils { -namespace Android { - -String get_app_native_lib_dir(); - -} // namespace Android -} // namespace GDMonoUtils - -#endif // __ANDROID__ - -#endif // ANDROID_UTILS_H diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index e9efc7626d..88366a6a03 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -216,6 +216,25 @@ String str_format(const char *p_format, ...) { #endif String str_format(const char *p_format, va_list p_list) { + char *buffer = str_format_new(p_format, p_list); + + String res(buffer); + memdelete_arr(buffer); + + return res; +} + +char *str_format_new(const char *p_format, ...) { + va_list list; + + va_start(list, p_format); + char *res = str_format_new(p_format, list); + va_end(list); + + return res; +} + +char *str_format_new(const char *p_format, va_list p_list) { va_list list; va_copy(list, p_list); @@ -230,8 +249,5 @@ String str_format(const char *p_format, va_list p_list) { gd_vsnprintf(buffer, len, p_format, list); va_end(list); - String res(buffer); - memdelete_arr(buffer); - - return res; + return buffer; } diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h index 565b9bb644..e7f02955bd 100644 --- a/modules/mono/utils/string_utils.h +++ b/modules/mono/utils/string_utils.h @@ -56,5 +56,7 @@ Error read_all_file_utf8(const String &p_path, String &r_content); String str_format(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_1_2; String str_format(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE_1_0; +char *str_format_new(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_1_2; +char *str_format_new(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE_1_0; #endif // STRING_FORMAT_H diff --git a/modules/opus/SCsub b/modules/opus/SCsub index 8af4f16a26..1db5b0987e 100644 --- a/modules/opus/SCsub +++ b/modules/opus/SCsub @@ -20,9 +20,6 @@ if env['builtin_opus']: "opus_multistream.c", "opus_multistream_encoder.c", "opus_multistream_decoder.c", - "opus_projection_encoder.c", - "opus_projection_decoder.c", - "mapping_matrix.c", "repacketizer.c", "analysis.c", @@ -56,10 +53,9 @@ if env['builtin_opus']: "celt/vq.c", #"celt/arm/arm_celt_map.c", #"celt/arm/armcpu.c", - #"celt/arm/celt_fft_ne10.c", - #"celt/arm/celt_mdct_ne10.c", + #"celt/arm/celt_ne10_fft.c", + #"celt/arm/celt_ne10_mdct.c", #"celt/arm/celt_neon_intr.c", - #"celt/arm/pitch_neon_intr.c", # Sync with silk_sources.mk "silk/CNG.c", @@ -117,7 +113,6 @@ if env['builtin_opus']: "silk/lin2log.c", "silk/log2lin.c", "silk/LPC_analysis_filter.c", - "silk/LPC_fit.c", "silk/LPC_inv_pred_gain.c", "silk/table_LSF_cos.c", "silk/NLSF2A.c", @@ -155,10 +150,12 @@ if env['builtin_opus']: "silk/fixed/find_pitch_lags_FIX.c", "silk/fixed/find_pred_coefs_FIX.c", "silk/fixed/noise_shape_analysis_FIX.c", + "silk/fixed/prefilter_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/solve_LS_FIX.c", "silk/fixed/warped_autocorrelation_FIX.c", "silk/fixed/apply_sine_window_FIX.c", "silk/fixed/autocorr_FIX.c", @@ -183,9 +180,11 @@ if env['builtin_opus']: "silk/float/LTP_analysis_filter_FLP.c", "silk/float/LTP_scale_ctrl_FLP.c", "silk/float/noise_shape_analysis_FLP.c", + "silk/float/prefilter_FLP.c", "silk/float/process_gains_FLP.c", "silk/float/regularize_correlations_FLP.c", "silk/float/residual_energy_FLP.c", + "silk/float/solve_LS_FLP.c", "silk/float/warped_autocorrelation_FLP.c", "silk/float/wrappers_FLP.c", "silk/float/autocorrelation_FLP.c", @@ -194,6 +193,7 @@ if env['builtin_opus']: "silk/float/energy_FLP.c", "silk/float/inner_product_FLP.c", "silk/float/k2a_FLP.c", + "silk/float/levinsondurbin_FLP.c", "silk/float/LPC_inv_pred_gain_FLP.c", "silk/float/pitch_analysis_core_FLP.c", "silk/float/scale_copy_vector_FLP.c", diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 957127fe61..857d640b43 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -949,7 +949,7 @@ String VisualScriptOperator::get_caption() const { //mathematic L"A + B", //OP_ADD, L"A - B", //OP_SUBTRACT, - L"A x B", //OP_MULTIPLY, + L"A \u00D7 B", //OP_MULTIPLY, L"A \u00F7 B", //OP_DIVIDE, L"\u00AC A", //OP_NEGATE, L"+ A", //OP_POSITIVE, diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp index 32beccde5d..9d610109ed 100644 --- a/modules/websocket/wsl_peer.cpp +++ b/modules/websocket/wsl_peer.cpp @@ -213,7 +213,7 @@ void WSLPeer::make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigne wslay_event_context_server_init(&(_data->ctx), &wsl_callbacks, _data); else wslay_event_context_client_init(&(_data->ctx), &wsl_callbacks, _data); - wslay_event_config_set_max_recv_msg_length(_data->ctx, (1 << p_in_buf_size)); + wslay_event_config_set_max_recv_msg_length(_data->ctx, (1ULL << p_in_buf_size)); } void WSLPeer::set_write_mode(WriteMode p_mode) { diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 9156181bbe..defee8f1f1 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -49,9 +49,6 @@ #include "java_godot_io_wrapper.h" #include "java_godot_wrapper.h" -#define PAN_GESTURE_MIN_DELTA 5 // only advertise PanGesture event with dx and dy greater than this -#define MAGNIFY_GESTURE_MIN_FACTOR 0.1 // only advertise MagnifyGesture event with a factor difference from 1.0 greater than this - class AndroidLogger : public Logger { public: virtual void logv(const char *p_format, va_list p_list, bool p_err) { @@ -409,35 +406,6 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> ERR_FAIL_COND(touch.size() != p_points.size()); - if (touch.size() == 1) { - Point2 d = (p_points[0].pos - touch.write[0].pos); - if (fabs(d.x) > PAN_GESTURE_MIN_DELTA || fabs(d.y) > PAN_GESTURE_MIN_DELTA) { - Ref<InputEventPanGesture> ev; - ev.instance(); - ev->set_position(p_points[0].pos); - ev->set_delta(d); - input->parse_input_event(ev); - touch.write[0].pos = p_points[0].pos; - } - } else if (touch.size() == 2) { - Point2 v0 = touch[1].pos - touch[0].pos; - float l0 = (v0.x * v0.x) + (v0.y * v0.y); - if (l0 != 0.0) { - Point2 v1 = p_points[1].pos - p_points[0].pos; - float l1 = (v1.x * v1.x) + (v1.y * v1.y); - float f = (l1 / l0); - if (fabs(f - 1.0) > MAGNIFY_GESTURE_MIN_FACTOR) { - Ref<InputEventMagnifyGesture> ev; - ev.instance(); - ev->set_position(p_points[0].pos + v1 / 2); - ev->set_factor(sqrt(f)); - input->parse_input_event(ev); - touch.write[0].pos = p_points[0].pos; - touch.write[1].pos = p_points[1].pos; - } - } - } - for (int i = 0; i < touch.size(); i++) { int idx = -1; @@ -452,7 +420,7 @@ void OS_Android::process_touch(int p_what, int p_pointer, const Vector<TouchPos> ERR_CONTINUE(idx == -1); if (touch[i].pos == p_points[idx].pos) - continue; //no unnecessary move + continue; //no move unncesearily Ref<InputEventScreenDrag> ev; ev.instance(); diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index a0d6ac9214..a63fa90067 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -82,10 +82,7 @@ def configure(env): env['CXX'] = 'em++' env['LINK'] = 'emcc' - # Emscripten's ar has issues with duplicate file names, so use cc. - env['AR'] = 'emcc' - env['ARFLAGS'] = '-o' - # emranlib is a noop, so it's safe to use with AR=emcc. + env['AR'] = 'emar' env['RANLIB'] = 'emranlib' # Use TempFileMunge since some AR invocations are too long for cmd.exe. @@ -127,6 +124,10 @@ def configure(env): ## Link flags + # We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to + # be linked explicitly. + env.Append(LIBS=['idbfs.js']) + env.Append(LINKFLAGS=['-s', 'BINARYEN=1']) # Allow increasing memory buffer size during runtime. This is efficient diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 7827c66841..ed9fc0ce51 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -819,8 +819,11 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { if (gn && gn->is_selected()) { Vector2 pos = (gn->get_drag_from() * zoom + drag_accum) / zoom; - if (is_using_snap()) { - int snap = get_snap(); + + // Snapping can be toggled temporarily by holding down Ctrl. + // This is done here as to not toggle the grid when holding down Ctrl. + if (is_using_snap() ^ Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + const int snap = get_snap(); pos = pos.snapped(Vector2(snap, snap)); } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 217dacfbfe..2a2a6bb41d 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -850,6 +850,11 @@ void Node::set_process_priority(int p_priority) { data.tree->make_group_changed("physics_process_internal"); } +int Node::get_process_priority() const { + + return data.process_priority; +} + void Node::set_process_input(bool p_enable) { if (p_enable == data.input) @@ -2754,6 +2759,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_process_delta_time"), &Node::get_process_delta_time); ClassDB::bind_method(D_METHOD("set_process", "enable"), &Node::set_process); ClassDB::bind_method(D_METHOD("set_process_priority", "priority"), &Node::set_process_priority); + ClassDB::bind_method(D_METHOD("get_process_priority"), &Node::get_process_priority); ClassDB::bind_method(D_METHOD("is_processing"), &Node::is_processing); ClassDB::bind_method(D_METHOD("set_process_input", "enable"), &Node::set_process_input); ClassDB::bind_method(D_METHOD("is_processing_input"), &Node::is_processing_input); @@ -2894,6 +2900,7 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority"); BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::REAL, "delta"))); BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::REAL, "delta"))); diff --git a/scene/main/node.h b/scene/main/node.h index a8bcd2f273..6d0ff7e5cf 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -350,6 +350,7 @@ public: bool is_processing_internal() const; void set_process_priority(int p_priority); + int get_process_priority() const; void set_process_input(bool p_enable); bool is_processing_input() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 78ceccfca2..3a6fff45c5 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -2066,7 +2066,7 @@ SceneTree::SceneTree() { int ref_atlas_subdiv = GLOBAL_DEF("rendering/quality/reflections/atlas_subdiv", 8); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_subdiv", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_subdiv", PROPERTY_HINT_RANGE, "0,32,or_greater")); //next_power_of_2 will return a 0 as min value int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,External 2x,External 4x")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x")); root->set_msaa(Viewport::MSAA(msaa_mode)); GLOBAL_DEF("rendering/quality/depth/hdr", true); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 563fcb9961..3ad44a4a2e 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3187,7 +3187,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_GROUP("Rendering", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,External 2x,External 4x"), "set_msaa", "get_msaa"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "get_hdr"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear"); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index fab0aace14..41bf7f4bf0 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1405,8 +1405,8 @@ void SpatialMaterial::set_texture(TextureParam p_param, const Ref<Texture> &p_te textures[p_param] = p_texture; RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); VS::get_singleton()->material_set_param(_get_material(), shader_names->texture_names[p_param], rid); - _queue_shader_change(); _change_notify(); + _queue_shader_change(); } Ref<Texture> SpatialMaterial::get_texture(TextureParam p_param) const { diff --git a/scene/resources/material.h b/scene/resources/material.h index 2423d6d48b..1c69a754b6 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -260,6 +260,8 @@ private: uint64_t proximity_fade : 1; uint64_t distance_fade : 2; uint64_t emission_op : 1; + uint64_t texture_metallic : 1; + uint64_t texture_roughness : 1; }; uint64_t key; @@ -305,6 +307,8 @@ private: mk.proximity_fade = proximity_fade_enabled; mk.distance_fade = distance_fade; mk.emission_op = emission_op; + mk.texture_metallic = textures[TEXTURE_METALLIC].is_valid() ? 1 : 0; + mk.texture_roughness = textures[TEXTURE_ROUGHNESS].is_valid() ? 1 : 0; return mk; } diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 9ee7c2936e..d56360f918 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -694,6 +694,11 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { return; } + Rect2 style_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + if (Math::is_zero_approx(style_rect.size.width) || Math::is_zero_approx(style_rect.size.height)) { + return; + } + bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0); bool aa_on = rounded_corners && anti_aliased; @@ -701,7 +706,6 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { bool blend_on = blend_border && draw_border; - Rect2 style_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); Rect2 border_style_rect = style_rect; if (aa_on && !blend_on) { float aa_size_grow = 0.5 * ((aa_size + 1) / 2); diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 9babc99349..316a94556d 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -3769,8 +3769,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha nv.sint = -cn->values[i].sint; } break; case TYPE_UINT: { - // FIXME: This can't work on uint - nv.uint = -cn->values[i].uint; + // Intentionally wrap the unsigned int value, because GLSL does. + nv.uint = 0 - cn->values[i].uint; } break; case TYPE_FLOAT: { nv.real = -cn->values[i].real; diff --git a/thirdparty/README.md b/thirdparty/README.md index 27cfe41238..9571ee49b9 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -397,19 +397,17 @@ Files extracted from the upstream source: ## opus - Upstream: https://opus-codec.org -- Version: 1.3.1 (opus) and 0.11 (opusfile) +- Version: 1.1.5 (opus) and 0.8 (opusfile) - License: BSD-3-Clause Files extracted from upstream source: -- Run `opus/configure` and copy/sync changes to `config.h` - (note that this file may have Godot-specific options enabled) - all .c and .h files in src/ (both opus and opusfile) - all .h files in include/ (both opus and opusfile) as opus/ - remove unused `opus_demo.c`, - remove `http.c`, `wincerts.c` and `winerrno.h` (part of unused libopusurl) -- celt/ and silk/ subfolders (minus tests folders) +- celt/ and silk/ subfolders - COPYING diff --git a/thirdparty/opus/analysis.c b/thirdparty/opus/analysis.c index cb46dec582..663431a436 100644 --- a/thirdparty/opus/analysis.c +++ b/thirdparty/opus/analysis.c @@ -29,29 +29,20 @@ #include "config.h" #endif -#define ANALYSIS_C - -#include <stdio.h> - -#include "mathops.h" #include "kiss_fft.h" #include "celt.h" #include "modes.h" #include "arch.h" #include "quant_bands.h" +#include <stdio.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, @@ -105,118 +96,52 @@ static const float analysis_window[240] = { }; 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 + 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120 }; -#define NB_TONAL_SKIP_BANDS 9 +static const int extra_bands[NB_TOT_BANDS+1] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200 +}; -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 const float tweight[NB_TBANDS+1] = { + .3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5 +};*/ -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); +#define NB_TONAL_SKIP_BANDS 9 - downmix(_x, tmp, subframe, offset, c1, c2, C); -#ifdef FIXED_POINT - scale = (1<<SIG_SHIFT); -#else - scale = 1.f/32768; -#endif - if (c2==-2) - scale /= C; - else if (c2>-1) - scale /= 2; - for (j=0;j<subframe;j++) - tmp[j] *= scale; - if (Fs == 48000) +#define cA 0.43157974f +#define cB 0.67848403f +#define cC 0.08595542f +#define cE ((float)M_PI/2) +static OPUS_INLINE float fast_atan2f(float y, float x) { + float x2, y2; + /* Should avoid underflow on the values we'll get */ + if (ABS16(x)+ABS16(y)<1e-9f) { - ret = silk_resampler_down2_hp(S, y, tmp, subframe); - } else if (Fs == 24000) { - OPUS_COPY(y, tmp, subframe); - } else if (Fs == 16000) { - VARDECL(opus_val32, tmp3x); - ALLOC(tmp3x, 3*subframe, opus_val32); - /* Don't do this at home! This resampler is horrible and it's only (barely) - usable for the purpose of the analysis because we don't care about all - the aliasing between 8 kHz and 12 kHz. */ - for (j=0;j<subframe;j++) - { - tmp3x[3*j] = tmp[j]; - tmp3x[3*j+1] = tmp[j]; - tmp3x[3*j+2] = tmp[j]; - } - silk_resampler_down2_hp(S, y, tmp3x, 3*subframe); + x*=1e12f; + y*=1e12f; + } + x2 = x*x; + y2 = y*y; + if(x2<y2){ + float den = (y2 + cB*x2) * (y2 + cC*x2); + if (den!=0) + return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE); + else + return (y<0 ? -cE : cE); + }else{ + float den = (x2 + cB*y2) * (x2 + cC*y2); + if (den!=0) + return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE); + else + return (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE); } - RESTORE_STACK; - return ret; } -void tonality_analysis_init(TonalityAnalysisState *tonal, opus_int32 Fs) +void tonality_analysis_init(TonalityAnalysisState *tonal) { /* Initialize reusable fields. */ tonal->arch = opus_select_arch(); - tonal->Fs = Fs; /* Clear remaining fields. */ tonality_analysis_reset(tonal); } @@ -232,34 +157,15 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int { int pos; int curr_lookahead; - float tonality_max; - float tonality_avg; - int tonality_count; + float psum; 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) + if (len > 480 && pos != tonal->write_pos) { pos++; if (pos==DETECT_SIZE) @@ -269,177 +175,32 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int 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;i<bandwidth_span;i++) - { - pos--; - if (pos < 0) - pos = DETECT_SIZE-1; - if (pos == tonal->write_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) + tonal->read_subframe += len/120; + while (tonal->read_subframe>=4) { - 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;i<IMIN(tonal->count-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); + tonal->read_subframe -= 4; + tonal->read_pos++; } - 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); + if (tonal->read_pos>=DETECT_SIZE) + tonal->read_pos-=DETECT_SIZE; - silence = (sample_max == 0); - (void)lsb_depth; - return silence; + /* Compensate for the delay in the features themselves. + FIXME: Need a better estimate the 10 I just made up */ + curr_lookahead = IMAX(curr_lookahead-10, 0); + + psum=0; + /* Summing the probability of transition patterns that involve music at + time (DETECT_SIZE-curr_lookahead-1) */ + for (i=0;i<DETECT_SIZE-curr_lookahead;i++) + psum += tonal->pmusic[i]; + for (;i<DETECT_SIZE;i++) + psum += tonal->pspeech[i]; + psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence; + /*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/ + + info_out->music_prob = psum; } -#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) { @@ -469,50 +230,24 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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; - } + tonal->last_transition++; + alpha = 1.f/IMIN(20, 1+tonal->count); + alphaE = 1.f/IMIN(50, 1+tonal->count); + alphaE2 = 1.f/IMIN(1000, 1+tonal->count); + if (tonal->count<4) + tonal->music_prob = .5; 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->count==0) + tonal->mem_fill = 240; + downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C); if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE) { tonal->mem_fill += len; @@ -520,13 +255,10 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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); @@ -541,20 +273,8 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt } 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); + downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C); 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. */ @@ -585,31 +305,24 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt d_angle2 = angle2 - angle; d2_angle2 = d_angle2 - d_angle; - mod1 = d2_angle - (float)float2int(d2_angle); + mod1 = d2_angle - (float)floor(.5+d2_angle); noisiness[i] = ABS16(mod1); mod1 *= mod1; mod1 *= mod1; - mod2 = d2_angle2 - (float)float2int(d2_angle2); + mod2 = d2_angle2 - (float)floor(.5+d2_angle2); noisiness[i] += ABS16(mod2); mod2 *= mod2; mod2 *= mod2; - avg_mod = .25f*(d2A[i]+mod1+2*mod2); - /* This introduces an extra delay of 2 frames in the detection. */ + avg_mod = .25f*(d2A[i]+2.f*mod1+mod2); tonality[i] = 1.f/(1.f+40.f*16.f*pi4*avg_mod)-.015f; - /* No delay on this detection, but it's less reliable. */ - tonality2[i] = 1.f/(1.f+40.f*16.f*pi4*mod2)-.015f; A[i] = angle2; dA[i] = d_angle2; d2A[i] = mod2; } - for (i=2;i<N2-1;i++) - { - float tt = MIN32(tonality2[i], MAX32(tonality2[i-1], tonality2[i+1])); - tonality[i] = .9f*MAX32(tonality[i], tt-.1f); - } + frame_tonality = 0; max_frame_tonality = 0; /*tw_sum = 0;*/ @@ -626,22 +339,6 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt } 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;b<NB_TBANDS;b++) { float E=0, tE=0, nE=0; @@ -651,9 +348,12 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt { 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; - binE = SCALE_ENER(binE); +#ifdef FIXED_POINT + /* FIXME: It's probably best to change the BFCC filter initial state instead */ + binE *= 5.55e-17f; +#endif E += binE; - tE += binE*MAX32(0, tonality[i]); + tE += binE*tonality[i]; nE += binE*2.f*(.5f-noisiness[i]); } #ifndef FIXED_POINT @@ -671,27 +371,14 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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) + tonal->lowE[b] = MIN32(logE[b], tonal->lowE[b]+.01f); + tonal->highE[b] = MAX32(logE[b], tonal->highE[b]-.1f); + if (tonal->highE[b] < tonal->lowE[b]+1.f) { - if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b]) - tonal->highE[b] -= .01f; - else - tonal->lowE[b] += .01f; + tonal->highE[b]+=.5f; + tonal->lowE[b]-=.5f; } - 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])); + relativeE += (logE[b]-tonal->lowE[b])/(1e-15f+tonal->highE[b]-tonal->lowE[b]); L1=L2=0; for (i=0;i<NB_FRAMES;i++) @@ -723,135 +410,45 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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<NB_TBANDS+1;b++) - { - float leak_slope = LEAKAGE_SLOPE*(tbands[b]-tbands[b-1])/4; - leakage_from[b] = MIN16(leakage_from[b-1]+leak_slope, band_log2[b]); - leakage_to[b] = MAX16(leakage_to[b-1]-leak_slope, band_log2[b]-LEAKAGE_OFFSET); - } - for (b=NB_TBANDS-2;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;b<NB_TBANDS+1;b++) - { - /* leak_boost[] is made up of two terms. The first, based on leakage_to[], - represents the boost needed to overcome the amount of analysis leakage - cause in a weaker band b by louder neighbouring bands. - The second, based on leakage_from[], applies to a loud band b for - which the quantization noise causes synthesis leakage to the weaker - neighbouring bands. */ - float boost = MAX16(0, leakage_to[b] - band_log2[b]) + - MAX16(0, band_log2[b] - (leakage_from[b]+LEAKAGE_OFFSET)); - info->leak_boost[b] = IMIN(255, (int)floor(.5 + 64.f*boost)); - } - for (;b<LEAK_BANDS;b++) info->leak_boost[b] = 0; - - for (i=0;i<NB_FRAMES;i++) - { - int j; - float mindist = 1e15f; - for (j=0;j<NB_FRAMES;j++) - { - int k; - float dist=0; - for (k=0;k<NB_TBANDS;k++) - { - float tmp; - tmp = tonal->logE[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))); +#ifdef FIXED_POINT + noise_floor *= 1<<(15+SIG_SHIFT); +#endif noise_floor *= noise_floor; - below_max_pitch=0; - above_max_pitch=0; - for (b=0;b<NB_TBANDS;b++) + for (b=0;b<NB_TOT_BANDS;b++) { float E=0; - float Em; int band_start, band_end; /* Keep a margin of 300 Hz for aliasing */ - band_start = tbands[b]; - band_end = tbands[b+1]; + band_start = extra_bands[b]; + band_end = extra_bands[b+1]; for (i=band_start;i<band_end;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); maxE = MAX32(maxE, E); - if (band_start < 64) - { - below_max_pitch += E; - } else { - above_max_pitch += E; - } tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E); - Em = MAX32(E, tonal->meanE[b]); + E = MAX32(E, tonal->meanE[b]); + /* Use a simple follower with 13 dB/Bark slope for spreading function */ + bandwidth_mask = MAX32(.05f*bandwidth_mask, E); /* Consider the band "active" only if all these conditions are met: - 1) less than 90 dB below the peak band (maximal masking possible considering + 1) less than 10 dB below the simple follower + 2) 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[] + 3) above the PCM quantization noise floor */ - 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); + if (E>.1*bandwidth_mask && E*1e9f > maxE && E > noise_floor*(band_end-band_start)) + bandwidth = b; } - /* 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->Etracker = MAX32(tonal->Etracker-.03f, frame_loudness); tonal->lowECount *= (1-alphaE); if (frame_loudness < tonal->Etracker-30) tonal->lowECount += alphaE; @@ -863,18 +460,11 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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; + relativeE = .5; frame_noisiness /= NB_TBANDS; #if 1 info->activity = frame_noisiness + (1-frame_noisiness)*relativeE; @@ -889,7 +479,7 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt info->tonality_slope = slope; tonal->E_count = (tonal->E_count+1)%NB_FRAMES; - tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX); + tonal->count++; info->tonality = frame_tonality; for (i=0;i<4;i++) @@ -908,8 +498,6 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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++) { @@ -919,31 +507,136 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt 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"); + features[11+i] = (float)sqrt(tonal->std[i]); + features[20] = info->tonality; + features[21] = info->activity; + features[22] = frame_stationarity; + features[23] = info->tonality_slope; + features[24] = tonal->lowECount; + +#ifndef DISABLE_FLOAT_API + mlp_process(&net, features, frame_probs); + frame_probs[0] = .5f*(frame_probs[0]+1); + /* Curve fitting between the MLP probability and the actual probability */ + frame_probs[0] = .01f + 1.21f*frame_probs[0]*frame_probs[0] - .23f*(float)pow(frame_probs[0], 10); + /* Probability of active audio (as opposed to silence) */ + frame_probs[1] = .5f*frame_probs[1]+.5f; + /* Consider that silence has a 50-50 probability. */ + frame_probs[0] = frame_probs[1]*frame_probs[0] + (1-frame_probs[1])*.5f; + + /*printf("%f %f ", frame_probs[0], frame_probs[1]);*/ + { + /* Probability of state transition */ + float tau; + /* Represents independence of the MLP probabilities, where + beta=1 means fully independent. */ + float beta; + /* Denormalized probability of speech (p0) and music (p1) after update */ + float p0, p1; + /* Probabilities for "all speech" and "all music" */ + float s0, m0; + /* Probability sum for renormalisation */ + float psum; + /* Instantaneous probability of speech and music, with beta pre-applied. */ + float speech0; + float music0; + float p, q; + + /* One transition every 3 minutes of active audio */ + tau = .00005f*frame_probs[1]; + /* Adapt beta based on how "unexpected" the new prob is */ + p = MAX16(.05f,MIN16(.95f,frame_probs[0])); + q = MAX16(.05f,MIN16(.95f,tonal->music_prob)); + beta = .01f+.05f*ABS16(p-q)/(p*(1-q)+q*(1-p)); + /* p0 and p1 are the probabilities of speech and music at this frame + using only information from previous frame and applying the + state transition model */ + p0 = (1-tonal->music_prob)*(1-tau) + tonal->music_prob *tau; + p1 = tonal->music_prob *(1-tau) + (1-tonal->music_prob)*tau; + /* We apply the current probability with exponent beta to work around + the fact that the probability estimates aren't independent. */ + p0 *= (float)pow(1-frame_probs[0], beta); + p1 *= (float)pow(frame_probs[0], beta); + /* Normalise the probabilities to get the Marokv probability of music. */ + tonal->music_prob = p1/(p0+p1); + info->music_prob = tonal->music_prob; + + /* This chunk of code deals with delayed decision. */ + psum=1e-20f; + /* Instantaneous probability of speech and music, with beta pre-applied. */ + speech0 = (float)pow(1-frame_probs[0], beta); + music0 = (float)pow(frame_probs[0], beta); + if (tonal->count==1) + { + tonal->pspeech[0]=.5; + tonal->pmusic [0]=.5; + } + /* Updated probability of having only speech (s0) or only music (m0), + before considering the new observation. */ + s0 = tonal->pspeech[0] + tonal->pspeech[1]; + m0 = tonal->pmusic [0] + tonal->pmusic [1]; + /* Updates s0 and m0 with instantaneous probability. */ + tonal->pspeech[0] = s0*(1-tau)*speech0; + tonal->pmusic [0] = m0*(1-tau)*music0; + /* Propagate the transition probabilities */ + for (i=1;i<DETECT_SIZE-1;i++) + { + tonal->pspeech[i] = tonal->pspeech[i+1]*speech0; + tonal->pmusic [i] = tonal->pmusic [i+1]*music0; + } + /* Probability that the latest frame is speech, when all the previous ones were music. */ + tonal->pspeech[DETECT_SIZE-1] = m0*tau*speech0; + /* Probability that the latest frame is music, when all the previous ones were speech. */ + tonal->pmusic [DETECT_SIZE-1] = s0*tau*music0; + + /* Renormalise probabilities to 1 */ + for (i=0;i<DETECT_SIZE;i++) + psum += tonal->pspeech[i] + tonal->pmusic[i]; + psum = 1.f/psum; + for (i=0;i<DETECT_SIZE;i++) + { + tonal->pspeech[i] *= psum; + tonal->pmusic [i] *= psum; + } + psum = tonal->pmusic[0]; + for (i=1;i<DETECT_SIZE;i++) + psum += tonal->pspeech[i]; + + /* Estimate our confidence in the speech/music decisions */ + if (frame_probs[1]>.75) + { + if (tonal->music_prob>.9) + { + float adapt; + adapt = 1.f/(++tonal->music_confidence_count); + tonal->music_confidence_count = IMIN(tonal->music_confidence_count, 500); + tonal->music_confidence += adapt*MAX16(-.2f,frame_probs[0]-tonal->music_confidence); + } + if (tonal->music_prob<.1) + { + float adapt; + adapt = 1.f/(++tonal->speech_confidence_count); + tonal->speech_confidence_count = IMIN(tonal->speech_confidence_count, 500); + tonal->speech_confidence += adapt*MIN16(.2f,frame_probs[0]-tonal->speech_confidence); + } + } else { + if (tonal->music_confidence_count==0) + tonal->music_confidence = .9f; + if (tonal->speech_confidence_count==0) + tonal->speech_confidence = .1f; + } + } + if (tonal->last_music != (tonal->music_prob>.5f)) + tonal->last_transition=0; + tonal->last_music = tonal->music_prob>.5f; +#else + info->music_prob = 0; #endif + /*for (i=0;i<25;i++) + printf("%f ", features[i]); + printf("\n");*/ info->bandwidth = bandwidth; - tonal->prev_bandwidth = bandwidth; /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/ info->noisiness = frame_noisiness; info->valid = 1; @@ -957,25 +650,23 @@ void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, co 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); + analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/100, 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; - } + do { + tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix); + offset += 480; + pcm_len -= 480; + } while (pcm_len>0); analysis->analysis_offset = analysis_frame_size; analysis->analysis_offset -= frame_size; } + analysis_info->valid = 0; tonality_get_info(analysis, analysis_info, frame_size); } - -#endif /* DISABLE_FLOAT_API */ diff --git a/thirdparty/opus/analysis.h b/thirdparty/opus/analysis.h index 0b66555f21..9eae56a525 100644 --- a/thirdparty/opus/analysis.h +++ b/thirdparty/opus/analysis.h @@ -30,24 +30,16 @@ #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 */ +#define NB_TOT_BANDS 21 +#define ANALYSIS_BUF_SIZE 720 /* 15 ms at 48 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*/ +#define DETECT_SIZE 200 typedef struct { int arch; - int application; - opus_int32 Fs; #define TONALITY_ANALYSIS_RESET_START angle float angle[240]; float d_angle[240]; @@ -56,27 +48,35 @@ typedef struct { 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 meanE[NB_TOT_BANDS]; float mem[32]; float cmean[8]; float std[9]; + float music_prob; float Etracker; float lowECount; int E_count; + int last_music; + int last_transition; int count; + float subframe_mem[3]; int analysis_offset; + /** Probability of having speech for time i to DETECT_SIZE-1 (and music before). + pspeech[0] is the probability that all frames in the window are speech. */ + float pspeech[DETECT_SIZE]; + /** Probability of having music for time i to DETECT_SIZE-1 (and speech before). + pmusic[0] is the probability that all frames in the window are music. */ + float pmusic[DETECT_SIZE]; + float speech_confidence; + float music_confidence; + int speech_confidence_count; + int music_confidence_count; 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; @@ -86,7 +86,7 @@ typedef struct { * 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); +void tonality_analysis_init(TonalityAnalysisState *analysis); /** Reset a TonalityAnalysisState stuct. * diff --git a/thirdparty/opus/celt/_kiss_fft_guts.h b/thirdparty/opus/celt/_kiss_fft_guts.h index 17392b3e90..5e3d58fd66 100644 --- a/thirdparty/opus/celt/_kiss_fft_guts.h +++ b/thirdparty/opus/celt/_kiss_fft_guts.h @@ -58,12 +58,12 @@ # 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) + do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32(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) + do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32(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 ) ;\ @@ -77,17 +77,17 @@ 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); \ + do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((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); \ + do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((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);\ + do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((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); \ + do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \ }while(0) #if defined(OPUS_ARM_INLINE_ASM) diff --git a/thirdparty/opus/celt/arch.h b/thirdparty/opus/celt/arch.h index 08b07db598..8ceab5fe10 100644 --- a/thirdparty/opus/celt/arch.h +++ b/thirdparty/opus/celt/arch.h @@ -46,50 +46,25 @@ # 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) +#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__); +#ifdef ENABLE_ASSERTIONS #include <stdio.h> #include <stdlib.h> #ifdef __GNUC__ __attribute__((noreturn)) #endif -void celt_fatal(const char *str, const char *file, int line) +static OPUS_INLINE 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) +#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);}} #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)) @@ -118,20 +93,14 @@ void celt_fatal(const char *str, const char *file, int line) 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 @@ -160,7 +129,7 @@ static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { #ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR #include "arm/fixed_arm64.h" -#elif defined (OPUS_ARM_INLINE_EDSP) +#elif OPUS_ARM_INLINE_EDSP #include "arm/fixed_armv5e.h" #elif defined (OPUS_ARM_INLINE_ASM) #include "arm/fixed_armv4.h" @@ -178,7 +147,6 @@ static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { typedef float opus_val16; typedef float opus_val32; -typedef float opus_val64; typedef float celt_sig; typedef float celt_norm; @@ -218,7 +186,6 @@ static OPUS_INLINE int celt_isnan(float 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) @@ -235,7 +202,6 @@ static OPUS_INLINE int celt_isnan(float 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)) @@ -243,8 +209,6 @@ static OPUS_INLINE int celt_isnan(float x) #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)) @@ -279,9 +243,9 @@ static OPUS_INLINE int celt_isnan(float x) #ifndef GLOBAL_STACK_SIZE #ifdef FIXED_POINT -#define GLOBAL_STACK_SIZE 120000 +#define GLOBAL_STACK_SIZE 100000 #else -#define GLOBAL_STACK_SIZE 120000 +#define GLOBAL_STACK_SIZE 100000 #endif #endif diff --git a/thirdparty/opus/celt/arm/arm2gnu.pl b/thirdparty/opus/celt/arm/arm2gnu.pl index a2895f7445..6c922ac819 100755 --- a/thirdparty/opus/celt/arm/arm2gnu.pl +++ b/thirdparty/opus/celt/arm/arm2gnu.pl @@ -164,11 +164,11 @@ while (<>) { $prefix = ""; if ($proc) { - $prefix = $prefix.sprintf("\t.type\t%s, %%function", $proc) unless ($apple); + $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."; "; + $prefix = "; "; push(@proc_stack, $proc); s/^[A-Za-z_\.]\w+/$symprefix$&:/; } diff --git a/thirdparty/opus/celt/arm/arm_celt_map.c b/thirdparty/opus/celt/arm/arm_celt_map.c index ca988b66f5..4d4d069a86 100644 --- a/thirdparty/opus/celt/arm/arm_celt_map.c +++ b/thirdparty/opus/celt/arm/arm_celt_map.c @@ -35,29 +35,12 @@ #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) = { + const opus_val16 *, opus_val32 *, int , int) = { celt_pitch_xcorr_c, /* ARMv4 */ MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */ MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */ @@ -68,7 +51,7 @@ opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *, # 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) = { + const opus_val16 *, opus_val32 *, int, int) = { celt_pitch_xcorr_c, /* ARMv4 */ celt_pitch_xcorr_c, /* EDSP */ celt_pitch_xcorr_c, /* Media */ diff --git a/thirdparty/opus/celt/arm/celt_fft_ne10.c b/thirdparty/opus/celt/arm/celt_ne10_fft.c index ea5fd7808b..42d96a7117 100644 --- a/thirdparty/opus/celt/arm/celt_fft_ne10.c +++ b/thirdparty/opus/celt/arm/celt_ne10_fft.c @@ -1,7 +1,7 @@ /* Copyright (c) 2015 Xiph.Org Foundation Written by Viswanath Puttagunta */ /** - @file celt_fft_ne10.c + @file celt_ne10_fft.c @brief ARM Neon optimizations for fft using NE10 library */ @@ -36,6 +36,7 @@ #endif #endif +#include <NE10_init.h> #include <NE10_dsp.h> #include "os_support.h" #include "kiss_fft.h" diff --git a/thirdparty/opus/celt/arm/celt_mdct_ne10.c b/thirdparty/opus/celt/arm/celt_ne10_mdct.c index 3531d02d10..293c3efd7a 100644 --- a/thirdparty/opus/celt/arm/celt_mdct_ne10.c +++ b/thirdparty/opus/celt/arm/celt_ne10_mdct.c @@ -1,7 +1,7 @@ /* Copyright (c) 2015 Xiph.Org Foundation Written by Viswanath Puttagunta */ /** - @file celt_mdct_ne10.c + @file celt_ne10_mdct.c @brief ARM Neon optimizations for mdct using NE10 library */ diff --git a/thirdparty/opus/celt/arm/celt_neon_intr.c b/thirdparty/opus/celt/arm/celt_neon_intr.c index effda769d0..47bbe3dc22 100644 --- a/thirdparty/opus/celt/arm/celt_neon_intr.c +++ b/thirdparty/opus/celt/arm/celt_neon_intr.c @@ -191,21 +191,121 @@ static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y, vst1q_f32(sum, SUMM); } +/* + * Function: xcorr_kernel_neon_float_process1 + * --------------------------------- + * Computes single correlation values and stores in *sum + */ +static void xcorr_kernel_neon_float_process1(const float32_t *x, + const float32_t *y, float32_t *sum, int len) { + float32x4_t XX[4]; + float32x4_t YY[4]; + float32x2_t XX_2; + float32x2_t YY_2; + float32x4_t SUMM; + float32x2_t SUMM_2[2]; + const float32_t *xi = x; + const float32_t *yi = y; + + SUMM = vdupq_n_f32(0); + + /* Work on 16 values per iteration */ + while (len >= 16) { + XX[0] = vld1q_f32(xi); + xi += 4; + XX[1] = vld1q_f32(xi); + xi += 4; + XX[2] = vld1q_f32(xi); + xi += 4; + XX[3] = vld1q_f32(xi); + xi += 4; + + YY[0] = vld1q_f32(yi); + yi += 4; + YY[1] = vld1q_f32(yi); + yi += 4; + YY[2] = vld1q_f32(yi); + yi += 4; + YY[3] = vld1q_f32(yi); + yi += 4; + + SUMM = vmlaq_f32(SUMM, YY[0], XX[0]); + SUMM = vmlaq_f32(SUMM, YY[1], XX[1]); + SUMM = vmlaq_f32(SUMM, YY[2], XX[2]); + SUMM = vmlaq_f32(SUMM, YY[3], XX[3]); + len -= 16; + } + + /* Work on 8 values */ + if (len >= 8) { + XX[0] = vld1q_f32(xi); + xi += 4; + XX[1] = vld1q_f32(xi); + xi += 4; + + YY[0] = vld1q_f32(yi); + yi += 4; + YY[1] = vld1q_f32(yi); + yi += 4; + + SUMM = vmlaq_f32(SUMM, YY[0], XX[0]); + SUMM = vmlaq_f32(SUMM, YY[1], XX[1]); + len -= 8; + } + + /* Work on 4 values */ + if (len >= 4) { + XX[0] = vld1q_f32(xi); + xi += 4; + YY[0] = vld1q_f32(yi); + yi += 4; + SUMM = vmlaq_f32(SUMM, YY[0], XX[0]); + len -= 4; + } + + /* Start accumulating results */ + SUMM_2[0] = vget_low_f32(SUMM); + if (len >= 2) { + /* While at it, consume 2 more values if available */ + XX_2 = vld1_f32(xi); + xi += 2; + YY_2 = vld1_f32(yi); + yi += 2; + SUMM_2[0] = vmla_f32(SUMM_2[0], YY_2, XX_2); + len -= 2; + } + SUMM_2[1] = vget_high_f32(SUMM); + SUMM_2[0] = vadd_f32(SUMM_2[0], SUMM_2[1]); + SUMM_2[0] = vpadd_f32(SUMM_2[0], SUMM_2[0]); + /* Ok, now we have result accumulated in SUMM_2[0].0 */ + + if (len > 0) { + /* Case when you have one value left */ + XX_2 = vld1_dup_f32(xi); + YY_2 = vld1_dup_f32(yi); + SUMM_2[0] = vmla_f32(SUMM_2[0], XX_2, YY_2); + } + + vst1_lane_f32(sum, SUMM_2[0], 0); +} + void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y, - opus_val32 *xcorr, int len, int max_pitch, int arch) { + opus_val32 *xcorr, int len, int max_pitch) { int i; - (void)arch; celt_assert(max_pitch > 0); - celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + celt_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. */ + /* In case max_pitch isn't multiple of 4 + * compute single correlation value per iteration + */ for (; i < max_pitch; i++) { - xcorr[i] = celt_inner_prod_neon(_x, _y+i, len); + xcorr_kernel_neon_float_process1((const float32_t *)_x, + (const float32_t *)_y+i, (float32_t *)xcorr+i, len); } } #endif diff --git a/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm-gnu.S b/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm-gnu.S index 10668e54a5..5b2ee55a10 100644 --- a/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm-gnu.S +++ b/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm-gnu.S @@ -44,7 +44,7 @@ .if OPUS_ARM_MAY_HAVE_NEON @ Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3 - .type xcorr_kernel_neon, %function; xcorr_kernel_neon: @ PROC +; xcorr_kernel_neon: @ PROC xcorr_kernel_neon_start: @ input: @ r3 = int len @@ -156,8 +156,8 @@ xcorr_kernel_neon_process1: .size xcorr_kernel_neon, .-xcorr_kernel_neon @ ENDP @ opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y, -@ opus_val32 *xcorr, int len, int max_pitch, int arch) - .type celt_pitch_xcorr_neon, %function; celt_pitch_xcorr_neon: @ PROC +@ opus_val32 *xcorr, int len, int max_pitch) +; celt_pitch_xcorr_neon: @ PROC @ input: @ r0 = opus_val16 *_x @ r1 = opus_val16 *_y @@ -171,8 +171,6 @@ xcorr_kernel_neon_process1: @ 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 @@ -262,7 +260,7 @@ celt_pitch_xcorr_neon_done: @ This will get used on ARMv7 devices without NEON, so it has been optimized @ to take advantage of dual-issuing where possible. - .type xcorr_kernel_edsp, %function; xcorr_kernel_edsp: @ PROC +; xcorr_kernel_edsp: @ PROC xcorr_kernel_edsp_start: @ input: @ r3 = int len @@ -346,7 +344,7 @@ xcorr_kernel_edsp_done: LDMFD sp!, {r2,r4,r5,pc} .size xcorr_kernel_edsp, .-xcorr_kernel_edsp @ ENDP - .type celt_pitch_xcorr_edsp, %function; celt_pitch_xcorr_edsp: @ PROC +; 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) @@ -363,8 +361,6 @@ xcorr_kernel_edsp_done: @ 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] diff --git a/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm.s b/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm.s index 6e873afc37..f96e0a88bb 100644 --- a/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm.s +++ b/thirdparty/opus/celt/arm/celt_pitch_xcorr_arm.s @@ -153,7 +153,7 @@ xcorr_kernel_neon_process1 ENDP ; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y, -; opus_val32 *xcorr, int len, int max_pitch, int arch) +; opus_val32 *xcorr, int len, int max_pitch) celt_pitch_xcorr_neon PROC ; input: ; r0 = opus_val16 *_x @@ -168,8 +168,6 @@ celt_pitch_xcorr_neon PROC ; 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 @@ -360,8 +358,6 @@ celt_pitch_xcorr_edsp PROC ; 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] diff --git a/thirdparty/opus/celt/arm/fft_arm.h b/thirdparty/opus/celt/arm/fft_arm.h index 0b78175f3a..0cb55d8e22 100644 --- a/thirdparty/opus/celt/arm/fft_arm.h +++ b/thirdparty/opus/celt/arm/fft_arm.h @@ -34,6 +34,7 @@ #if !defined(FFT_ARM_H) #define FFT_ARM_H +#include "config.h" #include "kiss_fft.h" #if defined(HAVE_ARM_NE10) diff --git a/thirdparty/opus/celt/arm/fixed_armv4.h b/thirdparty/opus/celt/arm/fixed_armv4.h index d84888a772..efb3b1896a 100644 --- a/thirdparty/opus/celt/arm/fixed_armv4.h +++ b/thirdparty/opus/celt/arm/fixed_armv4.h @@ -37,7 +37,7 @@ static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b) "#MULT16_32_Q16\n\t" "smull %0, %1, %2, %3\n\t" : "=&r"(rd_lo), "=&r"(rd_hi) - : "%r"(b),"r"(SHL32(a,16)) + : "%r"(b),"r"(a<<16) ); return rd_hi; } @@ -54,10 +54,10 @@ static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b) "#MULT16_32_Q15\n\t" "smull %0, %1, %2, %3\n\t" : "=&r"(rd_lo), "=&r"(rd_hi) - : "%r"(b), "r"(SHL32(a,16)) + : "%r"(b), "r"(a<<16) ); /*We intentionally don't OR in the high bit of rd_lo for speed.*/ - return SHL32(rd_hi,1); + return rd_hi<<1; } #define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b)) diff --git a/thirdparty/opus/celt/arm/fixed_armv5e.h b/thirdparty/opus/celt/arm/fixed_armv5e.h index 6bf73cbace..36a6321101 100644 --- a/thirdparty/opus/celt/arm/fixed_armv5e.h +++ b/thirdparty/opus/celt/arm/fixed_armv5e.h @@ -59,7 +59,7 @@ static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b) : "=r"(res) : "r"(b), "r"(a) ); - return SHL32(res,1); + return res<<1; } #define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b)) @@ -76,7 +76,7 @@ static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a, "#MAC16_32_Q15\n\t" "smlawb %0, %1, %2, %3;\n" : "=r"(res) - : "r"(SHL32(b,1)), "r"(a), "r"(c) + : "r"(b<<1), "r"(a), "r"(c) ); return res; } diff --git a/thirdparty/opus/celt/arm/mdct_arm.h b/thirdparty/opus/celt/arm/mdct_arm.h index 14200bac4b..49cbb44576 100644 --- a/thirdparty/opus/celt/arm/mdct_arm.h +++ b/thirdparty/opus/celt/arm/mdct_arm.h @@ -33,6 +33,7 @@ #if !defined(MDCT_ARM_H) #define MDCT_ARM_H +#include "config.h" #include "mdct.h" #if defined(HAVE_ARM_NE10) diff --git a/thirdparty/opus/celt/arm/pitch_arm.h b/thirdparty/opus/celt/arm/pitch_arm.h index bed8b04eac..14331169ee 100644 --- a/thirdparty/opus/celt/arm/pitch_arm.h +++ b/thirdparty/opus/celt/arm/pitch_arm.h @@ -30,47 +30,11 @@ # 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); + opus_val32 *xcorr, int len, int max_pitch); # endif # if defined(OPUS_ARM_MAY_HAVE_MEDIA) @@ -79,7 +43,7 @@ opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y, # 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); + opus_val32 *xcorr, int len, int max_pitch); # endif # if defined(OPUS_HAVE_RTCD) && \ @@ -88,17 +52,18 @@ opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y, (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); + const opus_val16 *, opus_val32 *, 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)) + xcorr, len, max_pitch)) # 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)) +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((void)(arch),PRESUME_NEON(celt_pitch_xcorr)(_x, _y, xcorr, len, max_pitch)) # endif @@ -134,24 +99,25 @@ extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])( /* 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); + opus_val32 *xcorr, int len, int max_pitch); #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); + const opus_val16 *, opus_val32 *, 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)) + xcorr, len, max_pitch)) # elif defined(OPUS_ARM_PRESUME_NEON_INTR) # define OVERRIDE_PITCH_XCORR (1) -# define celt_pitch_xcorr celt_pitch_xcorr_float_neon +# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \ + ((void)(arch),celt_pitch_xcorr_float_neon(_x, _y, xcorr, len, max_pitch)) # endif diff --git a/thirdparty/opus/celt/arm/pitch_neon_intr.c b/thirdparty/opus/celt/arm/pitch_neon_intr.c deleted file mode 100644 index 1ac38c433a..0000000000 --- a/thirdparty/opus/celt/arm/pitch_neon_intr.c +++ /dev/null @@ -1,290 +0,0 @@ -/*********************************************************************** -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 <arm_neon.h> -#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/thirdparty/opus/celt/bands.c b/thirdparty/opus/celt/bands.c index 2702963c37..87eaa6c031 100644 --- a/thirdparty/opus/celt/bands.c +++ b/thirdparty/opus/celt/bands.c @@ -65,19 +65,19 @@ opus_uint32 celt_lcg_rand(opus_uint32 seed) /* 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) +static 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); + celt_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); + celt_assert(x2<=32766); return 1+x2; } -int bitexact_log2tan(int isin,int icos) +static int bitexact_log2tan(int isin,int icos) { int lc; int ls; @@ -92,11 +92,10 @@ int bitexact_log2tan(int isin,int icos) #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) +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM) { int i, c, N; const opus_int16 *eBands = m->eBands; - (void)arch; N = m->shortMdctSize<<LM; c=0; do { for (i=0;i<end;i++) @@ -156,7 +155,7 @@ void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, cel #else /* 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) +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM) { int i, c, N; const opus_int16 *eBands = m->eBands; @@ -165,7 +164,7 @@ void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *band for (i=0;i<end;i++) { opus_val32 sum; - sum = 1e-27f + celt_inner_prod(&X[c*N+(eBands[i]<<LM)], &X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM, arch); + sum = 1e-27f + celt_inner_prod_c(&X[c*N+(eBands[i]<<LM)], &X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM); bandE[i+c*m->nbEBands] = celt_sqrt(sum); /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ } @@ -225,9 +224,9 @@ void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X, #endif j=M*eBands[i]; band_end = M*eBands[i+1]; - lg = SATURATE16(ADD32(bandLogE[i], SHL32((opus_val32)eMeans[i],6))); + lg = ADD16(bandLogE[i], SHL16((opus_val16)eMeans[i],6)); #ifndef FIXED_POINT - g = celt_exp2(MIN32(32.f, lg)); + g = celt_exp2(lg); #else /* Handle the integer part of the log energy */ shift = 16-(lg>>DB_SHIFT); @@ -242,12 +241,12 @@ void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X, /* Handle extreme gains with negative shift. */ if (shift<0) { - /* For shift <= -2 and g > 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) + /* For shift < -2 we'd be likely to overflow, so we're capping + the gain here. This shouldn't happen unless the bitstream is + already corrupted. */ + if (shift < -2) { - g = 16384; + g = 32767; shift = -2; } do { @@ -282,7 +281,7 @@ void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_mas N0 = m->eBands[i+1]-m->eBands[i]; /* depth in 1/8 bits */ - celt_sig_assert(pulses[i]>=0); + celt_assert(pulses[i]>=0); depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM; #ifdef FIXED_POINT @@ -361,30 +360,6 @@ void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_mas } } -/* Compute the weights to use for optimizing normalized distortion across - channels. We use the amplitude to weight square distortion, which means - that we use the square root of the value we would have been using if we - wanted to minimize the MSE in the non-normalized domain. This roughly - corresponds to some quick-and-dirty perceptual experiments I ran to - measure inter-aural masking (there doesn't seem to be any published data - on the topic). */ -static void compute_channel_weights(celt_ener Ex, celt_ener Ey, opus_val16 w[2]) -{ - celt_ener minE; -#ifdef FIXED_POINT - int shift; -#endif - minE = MIN32(Ex, Ey); - /* Adjustment to make the weights a bit more conservative. */ - Ex = ADD32(Ex, minE/3); - Ey = ADD32(Ey, minE/3); -#ifdef FIXED_POINT - shift = celt_ilog2(EPSILON+MAX32(Ex, Ey))-14; -#endif - w[0] = VSHR32(Ex, shift); - w[1] = VSHR32(Ey, shift); -} - static void intensity_stereo(const CELTMode *m, celt_norm * OPUS_RESTRICT X, const celt_norm * OPUS_RESTRICT Y, const celt_ener *bandE, int bandID, int N) { int i = bandID; @@ -478,7 +453,7 @@ static void stereo_merge(celt_norm * OPUS_RESTRICT X, celt_norm * OPUS_RESTRICT /* Decide whether we should spread the pulses in the current frame */ int spreading_decision(const CELTMode *m, const celt_norm *X, int *average, int last_decision, int *hf_average, int *tapset_decision, int update_hf, - int end, int C, int M, const int *spread_weight) + int end, int C, int M) { int i, c, N0; int sum = 0, nbBands=0; @@ -519,8 +494,8 @@ int spreading_decision(const CELTMode *m, const celt_norm *X, int *average, if (i>m->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]; + sum += tmp*256; + nbBands++; } } while (++c<C); @@ -544,7 +519,7 @@ int spreading_decision(const CELTMode *m, const celt_norm *X, int *average, /*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); + sum = celt_udiv(sum, nbBands); /* Recursive averaging */ sum = (sum+*average)>>1; *average = sum; @@ -672,7 +647,6 @@ static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo) struct band_ctx { int encode; - int resynth; const CELTMode *m; int i; int intensity; @@ -683,9 +657,6 @@ struct band_ctx { const celt_ener *bandE; opus_uint32 seed; int arch; - int theta_round; - int disable_inv; - int avoid_split_noise; }; struct split_ctx { @@ -743,35 +714,8 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, 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; - } - } + itheta = (itheta*(opus_int32)qn+8192)>>14; + /* 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) @@ -849,7 +793,7 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, } else if (stereo) { if (encode) { - inv = itheta > 8192 && !ctx->disable_inv; + inv = itheta > 8192; if (inv) { int j; @@ -866,9 +810,6 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, inv = ec_dec_bit_logp(ec, 2); } else inv = 0; - /* inv flag override to avoid problems with downmixing. */ - if (ctx->disable_inv) - inv = 0; itheta = 0; } qalloc = ec_tell_frac(ec) - tell; @@ -904,6 +845,11 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b, celt_norm *lowband_out) { +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !ctx->encode; +#endif int c; int stereo; celt_norm *x = X; @@ -928,7 +874,7 @@ static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, ctx->remaining_bits -= 1<<BITRES; b-=1<<BITRES; } - if (ctx->resynth) + if (resynth) x[0] = sign ? -NORM_SCALING : NORM_SCALING; x = Y; } while (++c<1+stereo); @@ -953,6 +899,11 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, int B0=B; opus_val16 mid=0, side=0; unsigned cm=0; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !ctx->encode; +#endif celt_norm *Y=NULL; int encode; const CELTMode *m; @@ -984,7 +935,8 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, fill = (fill&1)|(fill<<1); B = (B+1)>>1; - compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, LM, 0, &fill); + compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, + LM, 0, &fill); imid = sctx.imid; iside = sctx.iside; delta = sctx.delta; @@ -1018,20 +970,24 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, rebalance = ctx->remaining_bits; if (mbits >= sbits) { - cm = quant_partition(ctx, X, N, mbits, B, lowband, LM, + 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<<BITRES && itheta!=0) sbits += rebalance - (3<<BITRES); - cm |= quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM, + cm |= quant_partition(ctx, Y, N, sbits, B, + next_lowband2, LM, MULT16_16_P15(gain,side), fill>>B)<<(B0>>1); } else { - cm = quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM, + 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<<BITRES && itheta!=16384) mbits += rebalance - (3<<BITRES); - cm |= quant_partition(ctx, X, N, mbits, B, lowband, LM, + cm |= quant_partition(ctx, X, N, mbits, B, + lowband, LM, MULT16_16_P15(gain,mid), fill); } } else { @@ -1056,14 +1012,18 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, /* Finally do the actual quantization */ if (encode) { - cm = alg_quant(X, N, K, spread, B, ec, gain, ctx->resynth, ctx->arch); + cm = alg_quant(X, N, K, spread, B, ec +#ifdef RESYNTH + , gain +#endif + ); } 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) + if (resynth) { unsigned cm_mask; /* B can be as large as 16, so this shift might overflow an int on a @@ -1120,6 +1080,11 @@ static unsigned quant_band(struct band_ctx *ctx, celt_norm *X, int recombine=0; int longBlocks; unsigned cm=0; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !ctx->encode; +#endif int k; int encode; int tf_change; @@ -1186,10 +1151,11 @@ static unsigned quant_band(struct band_ctx *ctx, celt_norm *X, deinterleave_hadamard(lowband, N_B>>recombine, B0<<recombine, longBlocks); } - cm = quant_partition(ctx, X, N, b, B, lowband, LM, gain, fill); + cm = quant_partition(ctx, X, N, b, B, lowband, + LM, gain, fill); /* This code is used by the decoder and by the resynthesis-enabled encoder */ - if (ctx->resynth) + if (resynth) { /* Undo the sample reorganization going from time order to frequency order */ if (B0>1) @@ -1242,6 +1208,11 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm int inv = 0; opus_val16 mid=0, side=0; unsigned cm=0; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !ctx->encode; +#endif int mbits, sbits, delta; int itheta; int qalloc; @@ -1261,7 +1232,8 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm orig_fill = fill; - compute_theta(ctx, &sctx, X, Y, N, &b, B, B, LM, 1, &fill); + compute_theta(ctx, &sctx, X, Y, N, &b, B, B, + LM, 1, &fill); inv = sctx.inv; imid = sctx.imid; iside = sctx.iside; @@ -1309,13 +1281,13 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm 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); + 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) + if (resynth) { celt_norm tmp; X[0] = MULT16_16_Q15(mid, X[0]); @@ -1342,32 +1314,38 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm { /* 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); + 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<<BITRES && itheta!=0) sbits += rebalance - (3<<BITRES); /* 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); + cm |= quant_band(ctx, Y, N, sbits, B, + NULL, LM, NULL, + side, NULL, fill>>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); + cm = quant_band(ctx, Y, N, sbits, B, + NULL, LM, NULL, + side, NULL, fill>>B); rebalance = sbits - (rebalance-ctx->remaining_bits); if (rebalance > 3<<BITRES && itheta!=16384) mbits += rebalance - (3<<BITRES); /* 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); + cm |= quant_band(ctx, X, N, mbits, B, + lowband, LM, lowband_out, + Q15ONE, lowband_scratch, fill); } } /* This code is used by the decoder and by the resynthesis-enabled encoder */ - if (ctx->resynth) + if (resynth) { if (N!=2) stereo_merge(X, Y, mid, N, ctx->arch); @@ -1381,38 +1359,19 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm return cm; } -static void special_hybrid_folding(const CELTMode *m, celt_norm *norm, celt_norm *norm2, int start, int M, int dual_stereo) -{ - int n1, n2; - const opus_int16 * OPUS_RESTRICT eBands = m->eBands; - 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) + opus_uint32 *seed, int arch) { 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; @@ -1420,11 +1379,10 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, 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; + int resynth = !encode; #endif struct band_ctx ctx; SAVE_STACK; @@ -1437,24 +1395,9 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, ALLOC(_norm, C*(M*eBands[m->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); + /* We can use the last band as scratch space because we don't need that + scratch space for the last band. */ + lowband_scratch = X_+M*eBands[m->nbEBands-1]; lowband_offset = 0; ctx.bandE = bandE; @@ -1465,11 +1408,6 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, 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<end;i++) { opus_int32 tell; @@ -1492,7 +1430,6 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, else Y = NULL; N = M*eBands[i+1]-M*eBands[i]; - celt_assert(N > 0); tell = ec_tell_frac(ec); /* Compute how many bits we want to allocate to this band */ @@ -1508,15 +1445,8 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, 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; @@ -1527,7 +1457,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, Y = norm; lowband_scratch = NULL; } - if (last && !theta_rdo) + if (i==end-1) lowband_scratch = NULL; /* Get a conservative estimate of the collapse_mask's for the bands we're @@ -1542,11 +1472,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+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]; @@ -1579,79 +1505,13 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, } else { if (Y!=NULL) { - if (theta_rdo && i < intensity) - { - ec_ctx ec_save, ec_save2; - struct band_ctx ctx_save, ctx_save2; - opus_val32 dist0, dist1; - unsigned cm, cm2; - int nstart_bytes, nend_bytes, save_bytes; - unsigned char *bytes_buf; - unsigned char bytes_save[1275]; - opus_val16 w[2]; - compute_channel_weights(bandE[i], bandE[i+m->nbEBands], 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); - } + 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); + last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm); } y_cm = x_cm; } @@ -1661,9 +1521,6 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, /* Update the folding position only as long as we have 1 bit/sample depth. */ update_lowband = b>(N<<BITRES); - /* We only need to avoid noise on a split for the first band. After that, we - have folding. */ - ctx.avoid_split_noise = 0; } *seed = ctx.seed; diff --git a/thirdparty/opus/celt/bands.h b/thirdparty/opus/celt/bands.h index 422b32cf75..e8bef4bad0 100644 --- a/thirdparty/opus/celt/bands.h +++ b/thirdparty/opus/celt/bands.h @@ -36,15 +36,12 @@ #include "entdec.h" #include "rate.h" -opus_int16 bitexact_cos(opus_int16 x); -int bitexact_log2tan(int isin,int icos); - /** Compute the amplitude (sqrt energy) in each of the bands * @param m Mode data * @param X Spectrum * @param bandE Square root of the energy for each band (returned) */ -void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch); +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM); /*void compute_noise_energies(const CELTMode *m, const celt_sig *X, const opus_val16 *tonality, celt_ener *bandE);*/ @@ -72,7 +69,7 @@ void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X, int spreading_decision(const CELTMode *m, const celt_norm *X, int *average, int last_decision, int *hf_average, int *tapset_decision, int update_hf, - int end, int C, int M, const int *spread_weight); + int end, int C, int M); #ifdef MEASURE_NORM_MSE void measure_norm_mse(const CELTMode *m, float *X, float *X0, float *bandE, float *bandE0, int M, int N, int C); @@ -108,7 +105,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end, 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 M, int codedBands, opus_uint32 *seed, - int complexity, int arch, int disable_inv); + int arch); void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_masks, int LM, int C, int size, int start, diff --git a/thirdparty/opus/celt/celt.c b/thirdparty/opus/celt/celt.c index 9ce234695c..b121c51a1f 100644 --- a/thirdparty/opus/celt/celt.c +++ b/thirdparty/opus/celt/celt.c @@ -111,31 +111,26 @@ void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, t = MAC16_32_Q16(x[i], g10, x2); t = MAC16_32_Q16(t, g11, ADD32(x1,x3)); t = MAC16_32_Q16(t, g12, ADD32(x0,x4)); - t = SATURATE(t, SIG_SAT); y[i] = t; x4=SHL32(x[i-T+3],1); t = MAC16_32_Q16(x[i+1], g10, x1); t = MAC16_32_Q16(t, g11, ADD32(x0,x2)); t = MAC16_32_Q16(t, g12, ADD32(x4,x3)); - t = SATURATE(t, SIG_SAT); y[i+1] = t; x3=SHL32(x[i-T+4],1); t = MAC16_32_Q16(x[i+2], g10, x0); t = MAC16_32_Q16(t, g11, ADD32(x4,x1)); t = MAC16_32_Q16(t, g12, ADD32(x3,x2)); - t = SATURATE(t, SIG_SAT); y[i+2] = t; x2=SHL32(x[i-T+5],1); t = MAC16_32_Q16(x[i+3], g10, x4); t = MAC16_32_Q16(t, g11, ADD32(x3,x0)); t = MAC16_32_Q16(t, g12, ADD32(x2,x1)); - t = SATURATE(t, SIG_SAT); y[i+3] = t; x1=SHL32(x[i-T+6],1); t = MAC16_32_Q16(x[i+4], g10, x3); t = MAC16_32_Q16(t, g11, ADD32(x2,x4)); t = MAC16_32_Q16(t, g12, ADD32(x1,x0)); - t = SATURATE(t, SIG_SAT); y[i+4] = t; } #ifdef CUSTOM_MODES @@ -146,7 +141,6 @@ void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, t = MAC16_32_Q16(x[i], g10, x2); t = MAC16_32_Q16(t, g11, ADD32(x1,x3)); t = MAC16_32_Q16(t, g12, ADD32(x0,x4)); - t = SATURATE(t, SIG_SAT); y[i] = t; x4=x3; x3=x2; @@ -175,7 +169,6 @@ void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + MULT16_32_Q15(g10,x2) + MULT16_32_Q15(g11,ADD32(x1,x3)) + MULT16_32_Q15(g12,ADD32(x0,x4)); - y[i] = SATURATE(y[i], SIG_SAT); x4=x3; x3=x2; x2=x1; @@ -207,10 +200,6 @@ void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, OPUS_MOVE(y, x, N); return; } - /* When the gain is zero, T0 and/or T1 is set to zero. We need - to have then be at least 2 to avoid processing garbage data. */ - T0 = IMAX(T0, COMBFILTER_MINPERIOD); - T1 = IMAX(T1, COMBFILTER_MINPERIOD); g00 = MULT16_16_P15(g0, gains[tapset0][0]); g01 = MULT16_16_P15(g0, gains[tapset0][1]); g02 = MULT16_16_P15(g0, gains[tapset0][2]); @@ -236,7 +225,6 @@ void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + MULT16_32_Q15(MULT16_16_Q15(f,g10),x2) + MULT16_32_Q15(MULT16_16_Q15(f,g11),ADD32(x1,x3)) + MULT16_32_Q15(MULT16_16_Q15(f,g12),ADD32(x0,x4)); - y[i] = SATURATE(y[i], SIG_SAT); x4=x3; x3=x2; x2=x1; @@ -256,16 +244,11 @@ void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, } #endif /* OVERRIDE_comb_filter */ -/* TF change table. Positive values mean better frequency resolution (longer - effective window), whereas negative values mean better time resolution - (shorter effective window). The second index is computed as: - 4*isTransient + 2*tf_select + per_band_flag */ const signed char tf_select_table[4][8] = { - /*isTransient=0 isTransient=1 */ - {0, -1, 0, -1, 0,-1, 0,-1}, /* 2.5 ms */ - {0, -1, 0, -2, 1, 0, 1,-1}, /* 5 ms */ - {0, -2, 0, -3, 2, 0, 1,-1}, /* 10 ms */ - {0, -2, 0, -3, 3, 0, 1,-1}, /* 20 ms */ + {0, -1, 0, -1, 0,-1, 0,-1}, + {0, -1, 0, -2, 1, 0, 1,-1}, + {0, -2, 0, -3, 2, 0, 1,-1}, + {0, -2, 0, -3, 3, 0, 1,-1}, }; diff --git a/thirdparty/opus/celt/celt.h b/thirdparty/opus/celt/celt.h index 24b6b2b520..d1f7eb690d 100644 --- a/thirdparty/opus/celt/celt.h +++ b/thirdparty/opus/celt/celt.h @@ -50,8 +50,6 @@ extern "C" { #define CELTDecoder OpusCustomDecoder #define CELTMode OpusCustomMode -#define LEAK_BANDS 19 - typedef struct { int valid; float tonality; @@ -59,28 +57,18 @@ typedef struct { 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; + int bandwidth; +}AnalysisInfo; #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 */ +/* Expose this option again when variable framesize actually works */ +#define OPUS_FRAMESIZE_VARIABLE 5010 /**< Optimize the frame size dynamically */ + #define CELT_SET_PREDICTION_REQUEST 10002 /** Controls the use of interframe prediction. @@ -128,9 +116,6 @@ typedef struct { #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); @@ -209,13 +194,6 @@ static OPUS_INLINE int fromOpus(unsigned char c) 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, diff --git a/thirdparty/opus/celt/celt_decoder.c b/thirdparty/opus/celt/celt_decoder.c index e6efce9358..b978bb34d1 100644 --- a/thirdparty/opus/celt/celt_decoder.c +++ b/thirdparty/opus/celt/celt_decoder.c @@ -51,14 +51,6 @@ #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 @@ -81,7 +73,6 @@ struct OpusCustomDecoder { int downsample; int start, end; int signalling; - int disable_inv; int arch; /* Everything beyond this point gets cleared on a reset */ @@ -109,38 +100,6 @@ struct OpusCustomDecoder { /* 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); @@ -204,11 +163,6 @@ OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMod 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); @@ -223,36 +177,6 @@ void opus_custom_decoder_destroy(CELTDecoder *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;j<N;j++) - { - celt_sig tmp0, tmp1; - /* Add VERY_SMALL to x[] first to reduce dependency chain. */ - tmp0 = x0[j] + VERY_SMALL + m0; - tmp1 = x1[j] + VERY_SMALL + m1; - m0 = MULT16_32_Q15(coef0, tmp0); - m1 = MULT16_32_Q15(coef0, tmp1); - pcm[2*j ] = SCALEOUT(SIG2WORD16(tmp0)); - pcm[2*j+1] = SCALEOUT(SIG2WORD16(tmp1)); - } - mem[0] = m0; - mem[1] = m1; -} -#endif #ifndef RESYNTH static @@ -266,14 +190,6 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c opus_val16 coef0; VARDECL(celt_sig, scratch); SAVE_STACK; -#ifndef CUSTOM_MODES - /* Short version for common case. */ - if (downsample == 1 && C == 2 && !accum) - { - deemphasis_stereo_simple(in, pcm, N, coef[0], mem); - return; - } -#endif #ifndef FIXED_POINT (void)accum; celt_assert(accum==0); @@ -309,7 +225,7 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c /* Shortcut for the standard (non-custom modes) case */ for (j=0;j<N;j++) { - celt_sig tmp = x[j] + VERY_SMALL + m; + celt_sig tmp = x[j] + m + VERY_SMALL; m = MULT16_32_Q15(coef0, tmp); scratch[j] = tmp; } @@ -330,7 +246,7 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c { for (j=0;j<N;j++) { - celt_sig tmp = x[j] + VERY_SMALL + m; + celt_sig tmp = x[j] + m + VERY_SMALL; m = MULT16_32_Q15(coef0, tmp); y[j*C] = SCALEOUT(SIG2WORD16(tmp)); } @@ -417,7 +333,7 @@ void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M, downsample, silence); for (i=0;i<N;i++) - freq[i] = ADD32(HALF32(freq[i]), HALF32(freq2[i])); + freq[i] = HALF32(ADD32(freq[i],freq2[i])); for (b=0;b<B;b++) clt_mdct_backward(&mode->mdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); } else { @@ -429,12 +345,6 @@ void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], clt_mdct_backward(&mode->mdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch); } while (++c<CC); } - /* Saturate IMDCT output so that we can't overflow in the pitch postfilter - or in the */ - c=0; do { - for (i=0;i<N;i++) - out_syn[c][i] = SATURATE(out_syn[c][i], SIG_SAT); - } while (++c<CC); RESTORE_STACK; } @@ -477,6 +387,14 @@ static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM, } } +/* 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) + static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch) { int pitch_index; @@ -586,15 +504,12 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) celt_synthesis(mode, X, out_syn, oldBandE, start, effEnd, C, C, 0, LM, st->downsample, 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); + VARDECL(opus_val16, exc); if (loss_count == 0) { @@ -604,14 +519,8 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) 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; + ALLOC(exc, MAX_PERIOD, opus_val16); window = mode->window; c=0; do { opus_val16 decay; @@ -620,11 +529,13 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) celt_sig *buf; int extrapolation_offset; int extrapolation_len; + int exc_length; int j; buf = decode_mem[c]; - for (i=0;i<MAX_PERIOD+LPC_ORDER;i++) - exc[i-LPC_ORDER] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD-LPC_ORDER+i], SIG_SHIFT); + for (i=0;i<MAX_PERIOD;i++) { + exc[i] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD+i], SIG_SHIFT); + } if (loss_count == 0) { @@ -650,32 +561,22 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) #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;i<LPC_ORDER;i++) - sum += ABS16(lpc[c*LPC_ORDER+i]); - if (sum < 65535) break; - for (i=0;i<LPC_ORDER;i++) - { - tmp = MULT16_16_Q15(QCONST16(.99f,15), tmp); - lpc[c*LPC_ORDER+i] = MULT16_16_Q15(lpc[c*LPC_ORDER+i], tmp); - } - } -#endif } + /* 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); /* Initialize the LPC history with the samples just before the start of the region for which we're computing the excitation. */ { - /* Compute the excitation for exc_length samples before the loss. We need the copy - because celt_fir() cannot filter in-place. */ + opus_val16 lpc_mem[LPC_ORDER]; + for (i=0;i<LPC_ORDER;i++) + { + lpc_mem[i] = + ROUND16(buf[DECODE_BUFFER_SIZE-exc_length-1-i], SIG_SHIFT); + } + /* Compute the excitation for exc_length samples before the loss. */ celt_fir(exc+MAX_PERIOD-exc_length, lpc+c*LPC_ORDER, - fir_tmp, exc_length, LPC_ORDER, st->arch); - OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length); + exc+MAX_PERIOD-exc_length, exc_length, LPC_ORDER, lpc_mem, st->arch); } /* Check if the waveform is decaying, and if so how fast. @@ -729,8 +630,9 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) tmp = ROUND16( buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j], SIG_SHIFT); - S1 += SHR32(MULT16_16(tmp, tmp), 10); + S1 += SHR32(MULT16_16(tmp, tmp), 8); } + { opus_val16 lpc_mem[LPC_ORDER]; /* Copy the last decoded samples (prior to the overlap region) to @@ -742,10 +644,6 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) celt_iir(buf+DECODE_BUFFER_SIZE-N, lpc+c*LPC_ORDER, buf+DECODE_BUFFER_SIZE-N, extrapolation_len, LPC_ORDER, lpc_mem, st->arch); -#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 @@ -756,7 +654,7 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) for (i=0;i<extrapolation_len;i++) { opus_val16 tmp = ROUND16(buf[DECODE_BUFFER_SIZE-N+i], SIG_SHIFT); - S2 += SHR32(MULT16_16(tmp, tmp), 10); + S2 += SHR32(MULT16_16(tmp, tmp), 8); } /* This checks for an "explosion" in the synthesis. */ #ifdef FIXED_POINT @@ -864,7 +762,6 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat const opus_int16 *eBands; ALLOC_STACK; - VALIDATE_CELT_DECODER(st); mode = st->mode; nbEBands = mode->nbEBands; overlap = mode->overlap; @@ -1059,7 +956,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat ALLOC(pulses, nbEBands, int); ALLOC(fine_priority, nbEBands, int); - codedBands = clt_compute_allocation(mode, start, end, offsets, cap, + codedBands = compute_allocation(mode, start, end, offsets, cap, alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, fine_quant, fine_priority, C, LM, dec, 0, 0, 0); @@ -1082,8 +979,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat quant_all_bands(0, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks, NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, - len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, 0, - st->arch, st->disable_inv); + len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, st->arch); if (anti_collapse_rsv > 0) { @@ -1338,26 +1234,6 @@ int opus_custom_decoder_ctl(CELTDecoder * OPUS_RESTRICT st, int request, ...) *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; } diff --git a/thirdparty/opus/celt/celt_encoder.c b/thirdparty/opus/celt/celt_encoder.c index 44cb0850ab..3ee7a4d3f7 100644 --- a/thirdparty/opus/celt/celt_encoder.c +++ b/thirdparty/opus/celt/celt_encoder.c @@ -73,8 +73,8 @@ struct OpusCustomEncoder { int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ int loss_rate; int lsb_depth; + int variable_duration; int lfe; - int disable_inv; int arch; /* Everything beyond this point gets cleared on a reset */ @@ -98,7 +98,6 @@ struct OpusCustomEncoder { #endif int consec_transient; AnalysisInfo analysis; - SILKInfo silk_info; opus_val32 preemph_memE[2]; opus_val32 preemph_memD[2]; @@ -124,7 +123,6 @@ struct OpusCustomEncoder { /* 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) @@ -138,10 +136,9 @@ OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int 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]; */ + + 3*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; } @@ -181,6 +178,7 @@ static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode, st->start = 0; st->end = st->mode->effEBands; st->signalling = 1; + st->arch = arch; st->constrained_vbr = 1; @@ -225,8 +223,7 @@ void opus_custom_encoder_destroy(CELTEncoder *st) 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) + opus_val16 *tf_estimate, int *tf_chan) { int i; VARDECL(opus_val16, tmp); @@ -236,12 +233,6 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int 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, @@ -256,19 +247,6 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int 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<C;c++) { @@ -291,7 +269,7 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int mem0 = mem1 + y - 2*x; mem1 = x - .5f*y; #endif - tmp[i] = SROUND16(y, 2); + tmp[i] = EXTRACT16(SHR32(y,2)); /*printf("%f ", tmp[i]);*/ } /*printf("\n");*/ @@ -302,7 +280,7 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int /* Normalize tmp to max range */ { int shift=0; - shift = 14-celt_ilog2(MAX16(1, celt_maxabs16(tmp, len))); + shift = 14-celt_ilog2(1+celt_maxabs16(tmp, len)); if (shift!=0) { for (i=0;i<len;i++) @@ -321,9 +299,9 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int mean += x2; #ifdef FIXED_POINT /* FIXME: Use PSHR16() instead */ - tmp[i] = mem0 + PSHR32(x2-mem0,forward_shift); + tmp[i] = mem0 + PSHR32(x2-mem0,4); #else - tmp[i] = mem0 + MULT16_16_P15(forward_decay,x2-mem0); + tmp[i] = mem0 + MULT16_16_P15(QCONST16(.0625f,15),x2-mem0); #endif mem0 = tmp[i]; } @@ -333,7 +311,6 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int /* Backward pass to compute the pre-echo threshold */ for (i=len2-1;i>=0;i--) { - /* Backward masking: 13.9 dB/ms. */ #ifdef FIXED_POINT /* FIXME: Use PSHR16() instead */ tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3); @@ -362,12 +339,6 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int /* 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;i<len2-5;i+=4) { int id; @@ -388,12 +359,7 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int } } 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); */ @@ -583,7 +549,7 @@ static opus_val32 l1_metric(const celt_norm *tmp, int N, int LM, opus_val16 bias static int tf_analysis(const CELTMode *m, int len, int isTransient, int *tf_res, int lambda, celt_norm *X, int N0, int LM, - opus_val16 tf_estimate, int tf_chan, int *importance) + int *tf_sum, opus_val16 tf_estimate, int tf_chan) { int i; VARDECL(int, metric); @@ -608,6 +574,7 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient, ALLOC(path0, len, int); ALLOC(path1, len, int); + *tf_sum = 0; for (i=0;i<len;i++) { int k, N; @@ -662,26 +629,27 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient, metric[i] = 2*best_level; else metric[i] = -2*best_level; + *tf_sum += (isTransient ? LM : 0) - metric[i]/2; /* For bands that can't be split to -1, set the metric to the half-way point to avoid biasing the decision */ if (narrow && (metric[i]==0 || metric[i]==-2*LM)) metric[i]-=1; - /*printf("%d ", metric[i]/2 + (!isTransient)*LM);*/ + /*printf("%d ", metric[i]);*/ } /*printf("\n");*/ /* Search for the optimal tf resolution, including tf_select */ tf_select = 0; for (sel=0;sel<2;sel++) { - cost0 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*sel+0]); - cost1 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*sel+1]) + (isTransient ? 0 : lambda); + cost0 = 0; + cost1 = isTransient ? 0 : lambda; for (i=1;i<len;i++) { int curr0, curr1; curr0 = IMIN(cost0, cost1 + lambda); curr1 = IMIN(cost0 + lambda, cost1); - cost0 = curr0 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]); - cost1 = curr1 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]); + cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]); + cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]); } cost0 = IMIN(cost0, cost1); selcost[sel]=cost0; @@ -690,8 +658,8 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient, * If tests confirm it's useful for non-transients, we could allow it. */ if (selcost[1]<selcost[0] && isTransient) tf_select=1; - cost0 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]); - cost1 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]) + (isTransient ? 0 : lambda); + cost0 = 0; + cost1 = isTransient ? 0 : lambda; /* Viterbi forward pass */ for (i=1;i<len;i++) { @@ -719,8 +687,8 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient, curr1 = from1; path1[i]= 1; } - cost0 = curr0 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]); - cost1 = curr1 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]); + cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]); + cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]); } tf_res[len-1] = cost0 < cost1 ? 0 : 1; /* Viterbi backward pass to check the decisions */ @@ -786,7 +754,7 @@ static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM, static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X, const opus_val16 *bandLogE, int end, int LM, int C, int N0, AnalysisInfo *analysis, opus_val16 *stereo_saving, opus_val16 tf_estimate, - int intensity, opus_val16 surround_trim, opus_int32 equiv_rate, int arch) + int intensity, opus_val16 surround_trim, int arch) { int i; opus_val32 diff=0; @@ -794,14 +762,6 @@ static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X, int trim_index; opus_val16 trim = QCONST16(5.f, 8); opus_val16 logXC, logXC2; - /* At low bitrate, reducing the trim seems to help. At higher bitrates, it's less - clear what's best, so we're keeping it as it was before, at least for now. */ - if (equiv_rate < 64000) { - trim = QCONST16(4.f, 8); - } else if (equiv_rate < 80000) { - opus_int32 frac = (equiv_rate-64000) >> 10; - trim = QCONST16(4.f, 8) + QCONST16(1.f/16.f, 8)*frac; - } if (C==2) { opus_val16 sum = 0; /* Q10 */ @@ -849,7 +809,7 @@ static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X, } while (++c<C); diff /= C*(end-1); /*printf("%f\n", diff);*/ - trim -= MAX32(-QCONST16(2.f, 8), MIN32(QCONST16(2.f, 8), SHR32(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 )); + trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), SHR16(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 )); trim -= SHR16(surround_trim, DB_SHIFT-8); trim -= 2*SHR16(tf_estimate, 14-8); #ifndef DISABLE_FLOAT_API @@ -970,8 +930,7 @@ static opus_val16 median_of_3(const opus_val16 *x) 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 effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc) { int i, c; opus_int32 tot_boost=0; @@ -997,42 +956,6 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 for (i=0;i<end;i++) maxDepth = MAX16(maxDepth, bandLogE[c*nbEBands+i]-noise_floor[i]); } while (++c<C); - { - /* Compute a really simple masking model to avoid taking into account completely masked - bands when computing the spreading decision. */ - VARDECL(opus_val16, mask); - VARDECL(opus_val16, sig); - ALLOC(mask, nbEBands, opus_val16); - ALLOC(sig, nbEBands, opus_val16); - for (i=0;i<end;i++) - mask[i] = bandLogE[i]-noise_floor[i]; - if (C==2) - { - for (i=0;i<end;i++) - mask[i] = MAX16(mask[i], bandLogE[nbEBands+i]-noise_floor[i]); - } - OPUS_COPY(sig, mask, end); - for (i=1;i<end;i++) - mask[i] = MAX16(mask[i], mask[i-1] - QCONST16(2.f, DB_SHIFT)); - for (i=end-2;i>=0;i--) - mask[i] = MAX16(mask[i], mask[i+1] - QCONST16(3.f, DB_SHIFT)); - for (i=0;i<end;i++) - { - /* Compute SMR: Mask is never more than 72 dB below the peak and never below the noise floor.*/ - opus_val16 smr = sig[i]-MAX16(MAX16(0, maxDepth-QCONST16(12.f, DB_SHIFT)), mask[i]); - /* Clamp SMR to make sure we're not shifting by something negative or too large. */ -#ifdef FIXED_POINT - /* FIXME: Use PSHR16() instead */ - int shift = -PSHR32(MAX16(-QCONST16(5.f, DB_SHIFT), MIN16(0, smr)), DB_SHIFT); -#else - int shift = IMIN(5, IMAX(0, -(int)floor(.5f + smr))); -#endif - spread_weight[i] = 32 >> shift; - } - /*for (i=0;i<end;i++) - printf("%d ", spread_weight[i]); - printf("\n");*/ - } /* Make sure that dynamic allocation can't make us bust the budget */ if (effectiveBytes > 50 && LM>=1 && !lfe) { @@ -1089,14 +1012,6 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 } for (i=start;i<end;i++) follower[i] = MAX16(follower[i], surround_dynalloc[i]); - for (i=start;i<end;i++) - { -#ifdef FIXED_POINT - importance[i] = PSHR32(13*celt_exp2(MIN16(follower[i], QCONST16(4.f, DB_SHIFT))), 16); -#else - importance[i] = (int)floor(.5f+13*celt_exp2(MIN16(follower[i], QCONST16(4.f, DB_SHIFT)))); -#endif - } /* For non-transient CBR/CVBR frames, halve the dynalloc contribution */ if ((!vbr || constrained_vbr)&&!isTransient) { @@ -1105,26 +1020,14 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 } for (i=start;i<end;i++) { - if (i<8) - follower[i] *= 2; - if (i>=12) - follower[i] = HALF16(follower[i]); - } -#ifdef DISABLE_FLOAT_API - (void)analysis; -#else - if (analysis->valid) - { - for (i=start;i<IMIN(LEAK_BANDS, end);i++) - follower[i] = follower[i] + QCONST16(1.f/64.f, DB_SHIFT)*analysis->leak_boost[i]; - } -#endif - for (i=start;i<end;i++) - { int width; int boost; int boost_bits; + if (i<8) + follower[i] *= 2; + if (i>=12) + follower[i] = HALF16(follower[i]); follower[i] = MIN16(follower[i], QCONST16(4, DB_SHIFT)); width = C*(eBands[i+1]-eBands[i])<<LM; @@ -1139,11 +1042,11 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 boost = (int)SHR32(EXTEND32(follower[i])*width/6,DB_SHIFT); boost_bits = boost*6<<BITRES; } - /* For CBR and non-transient CVBR frames, limit dynalloc to 2/3 of the bits */ + /* For CBR and non-transient CVBR frames, limit dynalloc to 1/4 of the bits */ if ((!vbr || (constrained_vbr&&!isTransient)) - && (tot_boost+boost_bits)>>BITRES>>3 > 2*effectiveBytes/3) + && (tot_boost+boost_bits)>>BITRES>>3 > effectiveBytes/4) { - opus_int32 cap = ((2*effectiveBytes/3)<<BITRES<<3); + opus_int32 cap = ((effectiveBytes/4)<<BITRES<<3); offsets[i] = cap-tot_boost; tot_boost = cap; break; @@ -1152,9 +1055,6 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 tot_boost += boost_bits; } } - } else { - for (i=start;i<end;i++) - importance[i] = 13; } *tot_boost_ = tot_boost; RESTORE_STACK; @@ -1163,7 +1063,7 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem, int CC, int N, - int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes, AnalysisInfo *analysis) + int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes) { int c; VARDECL(celt_sig, _pre); @@ -1219,12 +1119,7 @@ static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem, 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); @@ -1298,7 +1193,7 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 int LM, opus_int32 bitrate, int lastCodedBands, int C, int intensity, int constrained_vbr, opus_val16 stereo_saving, int tot_boost, opus_val16 tf_estimate, int pitch_change, opus_val16 maxDepth, - int lfe, int has_surround_mask, opus_val16 surround_masking, + int variable_duration, int lfe, int has_surround_mask, opus_val16 surround_masking, opus_val16 temporal_vbr) { /* The target rate in 8th bits per frame */ @@ -1340,9 +1235,10 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 SHR32(MULT16_16(stereo_saving-QCONST16(0.1f,8),(coded_stereo_dof<<BITRES)),8)); } /* Boost the rate according to dynalloc (minus the dynalloc average for calibration). */ - target += tot_boost-(19<<LM); + target += tot_boost-(16<<LM); /* Apply transient boost, compensating for average boost. */ - tf_calibration = QCONST16(0.044f,14); + tf_calibration = variable_duration==OPUS_FRAMESIZE_VARIABLE ? + QCONST16(0.02f,14) : QCONST16(0.04f,14); target += (opus_int32)SHL32(MULT16_32_Q15(tf_estimate-tf_calibration, target),1); #ifndef DISABLE_FLOAT_API @@ -1353,7 +1249,7 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 float tonal; /* Tonality boost (compensating for the average). */ - tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f; + tonal = MAX16(0.f,analysis->tonality-.15f)-0.09f; tonal_target = target + (opus_int32)((coded_bins<<BITRES)*1.2f*tonal); if (pitch_change) tonal_target += (opus_int32)((coded_bins<<BITRES)*.8f); @@ -1383,11 +1279,21 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 /*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) + if ((!has_surround_mask||lfe) && (constrained_vbr || bitrate<64000)) { - target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target); + opus_val16 rate_factor = Q15ONE; + if (bitrate < 64000) + { +#ifdef FIXED_POINT + rate_factor = MAX16(0,(bitrate-32000)); +#else + rate_factor = MAX16(0,(1.f/32768)*(bitrate-32000)); +#endif + } + if (constrained_vbr) + rate_factor = MIN16(rate_factor, QCONST16(0.67f, 15)); + target = base_target + (opus_int32)MULT16_32_Q15(rate_factor, target-base_target); + } if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14)) @@ -1421,13 +1327,11 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; int shortBlocks=0; int isTransient=0; const int CC = st->channels; @@ -1439,6 +1343,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int end; int effEnd; int codedBands; + int tf_sum; int alloc_trim; int pitch_index=COMBFILTER_MINPERIOD; opus_val16 gain1 = 0; @@ -1450,7 +1355,6 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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; @@ -1472,10 +1376,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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; + opus_int32 equiv_rate = 510000; VARDECL(opus_val16, surround_dynalloc); ALLOC_STACK; @@ -1485,7 +1386,6 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, eBands = mode->eBands; start = st->start; end = st->end; - hybrid = start != 0; tf_estimate = 0; if (nbCompressedBytes<2 || pcm==NULL) { @@ -1509,14 +1409,12 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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; + tell=1; nbFilledBytes=0; } else { - tell0_frac=ec_tell_frac(enc); tell=ec_tell(enc); nbFilledBytes=(tell+4)>>3; } @@ -1569,11 +1467,10 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, if (st->bitrate!=OPUS_BITRATE_MAX) nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); - effectiveBytes = nbCompressedBytes - nbFilledBytes; + effectiveBytes = nbCompressedBytes; } - 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)); + equiv_rate = st->bitrate - (40*C+20)*((400>>LM) - 50); if (enc==NULL) { @@ -1661,17 +1558,17 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, { int enabled; int qg; - enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && !st->disable_pf - && st->complexity >= 5; + enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && start==0 && !silence && !st->disable_pf + && st->complexity >= 5 && !(st->consec_transient && LM!=3 && st->variable_duration==OPUS_FRAMESIZE_VARIABLE); 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); + pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes); 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) + if(start==0 && tell+16<=total_bits) ec_enc_bit_logp(enc, 0, 1); } else { /*This block is not gated by a total bits check only because @@ -1692,12 +1589,8 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, shortBlocks = 0; if (st->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); + &tf_estimate, &tf_chan); } if (LM>0 && ec_tell(enc)+3<=total_bits) { @@ -1717,19 +1610,16 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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); + compute_band_energies(mode, freq, bandE, effEnd, C, LM); amp2Log2(mode, effEnd, end, bandE, bandLogE2, C); for (i=0;i<C*nbEBands;i++) bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT)); } compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, 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); + compute_band_energies(mode, freq, bandE, effEnd, C, LM); if (st->lfe) { @@ -1744,7 +1634,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, ALLOC(surround_dynalloc, C*nbEBands, opus_val16); OPUS_CLEAR(surround_dynalloc, end); /* This computes how much masking takes place between surround channels */ - if (!hybrid&&st->energy_mask&&!st->lfe) + if (start==0&&st->energy_mask&&!st->lfe) { int mask_end; int midband; @@ -1846,14 +1736,14 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, /* 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 (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe) { 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); + compute_band_energies(mode, freq, bandE, effEnd, C, LM); amp2Log2(mode, effEnd, end, bandE, bandLogE, C); /* Compensate for the scaling of short vs long mdcts */ for (i=0;i<C*nbEBands;i++) @@ -1870,59 +1760,31 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, /* 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) + if (effectiveBytes>=15*C && start==0 && st->complexity>=2 && !st->lfe) { 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); + if (effectiveBytes<40) + lambda = 12; + else if (effectiveBytes<60) + lambda = 6; + else if (effectiveBytes<100) + lambda = 4; + else + lambda = 3; + lambda*=2; + tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, &tf_sum, tf_estimate, tf_chan); for (i=effEnd;i<end;i++) tf_res[i] = tf_res[effEnd-1]; - } else if (hybrid && weak_transient) - { - /* For weak transients, we rely on the fact that improving time resolution using - TF on a long window is imperfect and will not result in an energy collapse at - low bitrate. */ - for (i=0;i<end;i++) - tf_res[i] = 1; - tf_select=0; - } else if (hybrid && effectiveBytes<15 && st->silk_info.signalType != 2) - { - /* For low bitrate hybrid, we force temporal resolution to 5 ms rather than 2.5 ms. */ - for (i=0;i<end;i++) - tf_res[i] = 0; - tf_select=isTransient; } else { + tf_sum = 0; for (i=0;i<end;i++) tf_res[i] = isTransient; tf_select=0; } ALLOC(error, C*nbEBands, opus_val16); - c=0; - do { - for (i=start;i<end;i++) - { - /* When the energy is stable, slightly bias energy quantization towards - the previous error to make the gain more stable (a constant offset is - better than fluctuations). */ - if (ABS32(SUB32(bandLogE[i+c*nbEBands], oldBandE[i+c*nbEBands])) < QCONST16(2.f, DB_SHIFT)) - { - bandLogE[i+c*nbEBands] -= MULT16_16_Q15(energyError[i+c*nbEBands], QCONST16(0.25f, 15)); - } - } - } while (++c < C); quant_coarse_energy(mode, start, end, effEnd, bandLogE, oldBandE, total_bits, error, enc, C, LM, nbAvailableBytes, st->force_intra, @@ -1936,15 +1798,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, { 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) + } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C || start != 0) { if (st->complexity == 0) st->spread_decision = SPREAD_NONE; @@ -1968,7 +1822,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, { 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); + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M); } /*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);*/ @@ -1976,6 +1830,11 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); } + ALLOC(offsets, 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); /* For LFE, everything interesting is in the first band */ if (st->lfe) offsets[0] = IMIN(8, effectiveBytes/3); @@ -2037,15 +1896,12 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, alloc_trim = 5; if (tell+(6<<BITRES) <= total_bits - total_boost) { - if (start > 0 || st->lfe) - { - st->stereo_saving = 0; + if (st->lfe) alloc_trim = 5; - } else { + 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); - } + st->intensity, surround_trim, st->arch); ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); tell = ec_tell_frac(enc); } @@ -2063,36 +1919,17 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, /* 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)<<BITRES); - } else { - base_target = IMAX(0, vbr_rate - ((9*C+4)<<BITRES)); - } + base_target = vbr_rate - ((40*C+20)<<BITRES); if (st->constrained_vbr) base_target += (st->vbr_offset>>lm_diff); - if (!hybrid) - { - target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate, + 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, + st->variable_duration, 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<<BITRES)); - /* If we have a strong transient, let's make sure it has enough bits to code - the first two bands, so that it can use folding rather than noise. */ - if (tf_estimate > QCONST16(.7f,14)) - target = IMAX(target, 50<<BITRES); - } + /* The current offset is removed from the target and the space used so far is added*/ target=target+tell; @@ -2100,16 +1937,11 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, result in the encoder running out of bits. The margin of 2 bytes ensures that none of the bust-prevention logic in the decoder will have triggered so far. */ - min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(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)+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)); + min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes; nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); - nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes; /* By how much did we "miss" the target on that frame */ delta = target - vbr_rate; @@ -2156,7 +1988,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, st->vbr_reservoir = 0; /*printf ("+%d\n", adjust);*/ } - nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes); /*printf("%d\n", nbCompressedBytes*50*8);*/ /* This moves the raw bits to take into account the new compressed size */ ec_enc_shrink(enc, nbCompressedBytes); @@ -2191,7 +2023,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, #endif if (st->lfe) signalBandwidth = 1; - codedBands = clt_compute_allocation(mode, start, end, offsets, cap, + codedBands = 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) @@ -2206,7 +2038,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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<<BITRES)-anti_collapse_rsv, - balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch, st->disable_inv); + balance, enc, LM, codedBands, &st->rng, st->arch); if (anti_collapse_rsv > 0) { @@ -2217,14 +2049,6 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, 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;i<end;i++) - { - energyError[i+c*nbEBands] = MAX16(-QCONST16(0.5f, 15), MIN16(QCONST16(0.5f, 15), error[i+c*nbEBands])); - } - } while (++c < C); if (silence) { @@ -2497,24 +2321,10 @@ int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...) *value=st->lsb_depth; } break; - case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + case OPUS_SET_EXPERT_FRAME_DURATION_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; + st->variable_duration = value; } break; case OPUS_RESET_STATE: @@ -2558,13 +2368,6 @@ int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...) 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**); diff --git a/thirdparty/opus/celt/celt_lpc.c b/thirdparty/opus/celt/celt_lpc.c index 8ecb693ee9..b410a21c5f 100644 --- a/thirdparty/opus/celt/celt_lpc.c +++ b/thirdparty/opus/celt/celt_lpc.c @@ -89,40 +89,58 @@ int p void celt_fir_c( - const opus_val16 *x, + const opus_val16 *_x, const opus_val16 *num, - opus_val16 *y, + opus_val16 *_y, int N, int ord, + opus_val16 *mem, int arch) { int i,j; VARDECL(opus_val16, rnum); + VARDECL(opus_val16, x); SAVE_STACK; - celt_assert(x != y); + ALLOC(rnum, ord, opus_val16); + ALLOC(x, N+ord, opus_val16); for(i=0;i<ord;i++) rnum[i] = num[ord-i-1]; + for(i=0;i<ord;i++) + x[i] = mem[ord-i-1]; + for (i=0;i<N;i++) + x[i+ord]=_x[i]; + for(i=0;i<ord;i++) + mem[i] = _x[N-i-1]; +#ifdef SMALL_FOOTPRINT + (void)arch; + for (i=0;i<N;i++) + { + opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT); + for (j=0;j<ord;j++) + { + sum = MAC16_16(sum,rnum[j],x[i+j]); + } + _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT)); + } +#else for (i=0;i<N-3;i+=4) { - opus_val32 sum[4]; - sum[0] = SHL32(EXTEND32(x[i ]), SIG_SHIFT); - sum[1] = SHL32(EXTEND32(x[i+1]), SIG_SHIFT); - sum[2] = SHL32(EXTEND32(x[i+2]), SIG_SHIFT); - sum[3] = SHL32(EXTEND32(x[i+3]), SIG_SHIFT); - xcorr_kernel(rnum, x+i-ord, sum, ord, arch); - y[i ] = ROUND16(sum[0], SIG_SHIFT); - y[i+1] = ROUND16(sum[1], SIG_SHIFT); - y[i+2] = ROUND16(sum[2], SIG_SHIFT); - y[i+3] = ROUND16(sum[3], SIG_SHIFT); + opus_val32 sum[4]={0,0,0,0}; + xcorr_kernel(rnum, x+i, sum, ord, arch); + _y[i ] = SATURATE16(ADD32(EXTEND32(_x[i ]), PSHR32(sum[0], SIG_SHIFT))); + _y[i+1] = SATURATE16(ADD32(EXTEND32(_x[i+1]), PSHR32(sum[1], SIG_SHIFT))); + _y[i+2] = SATURATE16(ADD32(EXTEND32(_x[i+2]), PSHR32(sum[2], SIG_SHIFT))); + _y[i+3] = SATURATE16(ADD32(EXTEND32(_x[i+3]), PSHR32(sum[3], SIG_SHIFT))); } for (;i<N;i++) { - opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT); + opus_val32 sum = 0; for (j=0;j<ord;j++) - sum = MAC16_16(sum,rnum[j],x[i+j-ord]); - y[i] = ROUND16(sum, SIG_SHIFT); + sum = MAC16_16(sum,rnum[j],x[i+j]); + _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT))); } +#endif RESTORE_STACK; } @@ -148,7 +166,7 @@ void celt_iir(const opus_val32 *_x, { mem[j]=mem[j-1]; } - mem[0] = SROUND16(sum, SIG_SHIFT); + mem[0] = ROUND16(sum,SIG_SHIFT); _y[i] = sum; } #else @@ -177,20 +195,20 @@ void celt_iir(const opus_val32 *_x, xcorr_kernel(rden, y+i, sum, ord, arch); /* Patch up the result to compensate for the fact that this is an IIR */ - y[i+ord ] = -SROUND16(sum[0],SIG_SHIFT); + y[i+ord ] = -ROUND16(sum[0],SIG_SHIFT); _y[i ] = sum[0]; sum[1] = MAC16_16(sum[1], y[i+ord ], den[0]); - y[i+ord+1] = -SROUND16(sum[1],SIG_SHIFT); + y[i+ord+1] = -ROUND16(sum[1],SIG_SHIFT); _y[i+1] = sum[1]; sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]); sum[2] = MAC16_16(sum[2], y[i+ord ], den[1]); - y[i+ord+2] = -SROUND16(sum[2],SIG_SHIFT); + y[i+ord+2] = -ROUND16(sum[2],SIG_SHIFT); _y[i+2] = sum[2]; sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]); sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]); sum[3] = MAC16_16(sum[3], y[i+ord ], den[2]); - y[i+ord+3] = -SROUND16(sum[3],SIG_SHIFT); + y[i+ord+3] = -ROUND16(sum[3],SIG_SHIFT); _y[i+3] = sum[3]; } for (;i<N;i++) @@ -198,7 +216,7 @@ void celt_iir(const opus_val32 *_x, opus_val32 sum = _x[i]; for (j=0;j<ord;j++) sum -= MULT16_16(rden[j],y[i+j]); - y[i+ord] = SROUND16(sum,SIG_SHIFT); + y[i+ord] = ROUND16(sum,SIG_SHIFT); _y[i] = sum; } for(i=0;i<ord;i++) diff --git a/thirdparty/opus/celt/celt_lpc.h b/thirdparty/opus/celt/celt_lpc.h index a4c5fd6ea5..323459eb1a 100644 --- a/thirdparty/opus/celt/celt_lpc.h +++ b/thirdparty/opus/celt/celt_lpc.h @@ -45,11 +45,12 @@ void celt_fir_c( opus_val16 *y, int N, int ord, + opus_val16 *mem, 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)) +#define celt_fir(x, num, y, N, ord, mem, arch) \ + (celt_fir_c(x, num, y, N, ord, mem, arch)) #endif void celt_iir(const opus_val32 *x, diff --git a/thirdparty/opus/celt/cwrs.c b/thirdparty/opus/celt/cwrs.c index a552e4f0fb..9722f0ac86 100644 --- a/thirdparty/opus/celt/cwrs.c +++ b/thirdparty/opus/celt/cwrs.c @@ -482,7 +482,7 @@ static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){ k0=_k; q=row[_n]; if(q>_i){ - celt_sig_assert(p>q); + celt_assert(p>q); _k=_n; do p=CELT_PVQ_U_ROW[--_k][_n]; while(p>_i); diff --git a/thirdparty/opus/celt/entcode.h b/thirdparty/opus/celt/entcode.h index 3763e3f284..13d6c84ef0 100644 --- a/thirdparty/opus/celt/entcode.h +++ b/thirdparty/opus/celt/entcode.h @@ -122,7 +122,7 @@ 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); + celt_assert(d>0); #ifdef USE_SMALL_DIV_TABLE if (d>256) return n/d; @@ -138,7 +138,7 @@ static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) { } static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) { - celt_sig_assert(d>0); + celt_assert(d>0); #ifdef USE_SMALL_DIV_TABLE if (n<0) return -(opus_int32)celt_udiv(-n, d); diff --git a/thirdparty/opus/celt/entdec.h b/thirdparty/opus/celt/entdec.h index 025fc1870d..d8ab318730 100644 --- a/thirdparty/opus/celt/entdec.h +++ b/thirdparty/opus/celt/entdec.h @@ -85,7 +85,7 @@ int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); 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. + This must be at least one, and no more than 2**32-1. Return: The decoded bits.*/ opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); diff --git a/thirdparty/opus/celt/entenc.h b/thirdparty/opus/celt/entenc.h index f502eaf662..796bc4d572 100644 --- a/thirdparty/opus/celt/entenc.h +++ b/thirdparty/opus/celt/entenc.h @@ -67,7 +67,7 @@ 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.*/ + This must be at least one, 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. diff --git a/thirdparty/opus/celt/fixed_debug.h b/thirdparty/opus/celt/fixed_debug.h index f435295234..d28227f5dc 100644 --- a/thirdparty/opus/celt/fixed_debug.h +++ b/thirdparty/opus/celt/fixed_debug.h @@ -59,14 +59,6 @@ extern opus_int64 celt_mips; #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; @@ -235,11 +227,12 @@ static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line) #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 SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + #define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) static OPUS_INLINE short ADD16_(int a, int b, char *file, int line) { diff --git a/thirdparty/opus/celt/fixed_generic.h b/thirdparty/opus/celt/fixed_generic.h index 5f4abda76e..1cfd6d6989 100644 --- a/thirdparty/opus/celt/fixed_generic.h +++ b/thirdparty/opus/celt/fixed_generic.h @@ -104,9 +104,6 @@ /** 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)) @@ -120,14 +117,6 @@ /** 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)))) diff --git a/thirdparty/opus/celt/float_cast.h b/thirdparty/opus/celt/float_cast.h index 889dae965f..ed5a39b543 100644 --- a/thirdparty/opus/celt/float_cast.h +++ b/thirdparty/opus/celt/float_cast.h @@ -61,13 +61,7 @@ ** the config.h file. */ -/* With GCC, when SSE is available, the fastest conversion is cvtss2si. */ -#if defined(__GNUC__) && defined(__SSE__) - -#include <xmmintrin.h> -static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));} - -#elif defined(HAVE_LRINTF) +#if (HAVE_LRINTF) /* These defines enable functionality introduced with the 1999 ISO C ** standard. They must be defined before the inclusion of math.h to @@ -96,10 +90,10 @@ static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_s #include <math.h> #define float2int(x) lrint(x) -#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_X64) #include <xmmintrin.h> - static __inline long int float2int(float value) + __inline long int float2int(float value) { return _mm_cvtss_si32(_mm_load_ss(&value)); } @@ -110,7 +104,7 @@ static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_s ** Therefore implement OPUS_INLINE versions of these functions here. */ - static __inline long int + __inline long int float2int (float flt) { int intgr; diff --git a/thirdparty/opus/celt/kiss_fft.c b/thirdparty/opus/celt/kiss_fft.c index 83775165d8..1f8fd05321 100644 --- a/thirdparty/opus/celt/kiss_fft.c +++ b/thirdparty/opus/celt/kiss_fft.c @@ -82,8 +82,8 @@ static void kf_bfly2( C_SUB( Fout2[0] , Fout[0] , t ); C_ADDTO( Fout[0] , t ); - t.r = S_MUL(ADD32_ovflw(Fout2[1].r, Fout2[1].i), tw); - t.i = S_MUL(SUB32_ovflw(Fout2[1].i, Fout2[1].r), tw); + t.r = S_MUL(Fout2[1].r+Fout2[1].i, tw); + t.i = S_MUL(Fout2[1].i-Fout2[1].r, tw); C_SUB( Fout2[1] , Fout[1] , t ); C_ADDTO( Fout[1] , t ); @@ -92,8 +92,8 @@ static void kf_bfly2( C_SUB( Fout2[2] , Fout[2] , t ); C_ADDTO( Fout[2] , t ); - t.r = S_MUL(SUB32_ovflw(Fout2[3].i, Fout2[3].r), tw); - t.i = S_MUL(NEG32_ovflw(ADD32_ovflw(Fout2[3].i, Fout2[3].r)), tw); + t.r = S_MUL(Fout2[3].i-Fout2[3].r, tw); + t.i = S_MUL(-Fout2[3].i-Fout2[3].r, tw); C_SUB( Fout2[3] , Fout[3] , t ); C_ADDTO( Fout[3] , t ); Fout += 8; @@ -126,10 +126,10 @@ static void kf_bfly4( C_ADDTO( *Fout , scratch1 ); C_SUB( scratch1 , Fout[1] , Fout[3] ); - Fout[1].r = ADD32_ovflw(scratch0.r, scratch1.i); - Fout[1].i = SUB32_ovflw(scratch0.i, scratch1.r); - Fout[3].r = SUB32_ovflw(scratch0.r, scratch1.i); - Fout[3].i = ADD32_ovflw(scratch0.i, scratch1.r); + Fout[1].r = scratch0.r + scratch1.i; + Fout[1].i = scratch0.i - scratch1.r; + Fout[3].r = scratch0.r - scratch1.i; + Fout[3].i = scratch0.i + scratch1.r; Fout+=4; } } else { @@ -160,10 +160,10 @@ static void kf_bfly4( tw3 += fstride*3; C_ADDTO( *Fout , scratch[3] ); - Fout[m].r = ADD32_ovflw(scratch[5].r, scratch[4].i); - Fout[m].i = SUB32_ovflw(scratch[5].i, scratch[4].r); - Fout[m3].r = SUB32_ovflw(scratch[5].r, scratch[4].i); - Fout[m3].i = ADD32_ovflw(scratch[5].i, scratch[4].r); + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; ++Fout; } } @@ -212,18 +212,18 @@ static void kf_bfly3( 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)); + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = 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[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = 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[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; ++Fout; } while(--k); @@ -282,22 +282,22 @@ static void kf_bfly5( C_ADD( scratch[8],scratch[2],scratch[3]); C_SUB( scratch[9],scratch[2],scratch[3]); - Fout0->r = 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)); + Fout0->r += scratch[7].r + scratch[8].r; + Fout0->i += 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[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + 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))); + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -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)); + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = 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]); diff --git a/thirdparty/opus/celt/mathops.c b/thirdparty/opus/celt/mathops.c index 6ee9b9e101..21a01f52e4 100644 --- a/thirdparty/opus/celt/mathops.c +++ b/thirdparty/opus/celt/mathops.c @@ -38,8 +38,7 @@ #include "mathops.h" /*Compute floor(sqrt(_val)) with exact arithmetic. - _val must be greater than 0. - This has been tested on all possible 32-bit inputs greater than 0.*/ + This has been tested on all possible 32-bit inputs.*/ unsigned isqrt32(opus_uint32 _val){ unsigned b; unsigned g; @@ -183,7 +182,7 @@ opus_val32 celt_rcp(opus_val32 x) int i; opus_val16 n; opus_val16 r; - celt_sig_assert(x>0); + celt_assert2(x>0, "celt_rcp() only defined for positive values"); i = celt_ilog2(x); /* n is Q15 with range [0,1). */ n = VSHR32(x,i-15)-32768; diff --git a/thirdparty/opus/celt/mathops.h b/thirdparty/opus/celt/mathops.h index 5e86ff0dd2..a0525a9610 100644 --- a/thirdparty/opus/celt/mathops.h +++ b/thirdparty/opus/celt/mathops.h @@ -38,44 +38,11 @@ #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<y2){ - float den = (y2 + cB*x2) * (y2 + cC*x2); - return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE); - }else{ - float den = (x2 + cB*y2) * (x2 + cC*y2); - return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE); - } -} -#undef cA -#undef cB -#undef cC -#undef cE -#endif - - #ifndef OVERRIDE_CELT_MAXABS16 static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len) { @@ -113,6 +80,7 @@ static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len) #ifndef FIXED_POINT +#define PI 3.141592653f #define celt_sqrt(x) ((float)sqrt(x)) #define celt_rsqrt(x) (1.f/celt_sqrt(x)) #define celt_rsqrt_norm(x) (celt_rsqrt(x)) @@ -179,7 +147,7 @@ static OPUS_INLINE float celt_exp2(float x) /** 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); + celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers"); return EC_ILOG(x)-1; } #endif diff --git a/thirdparty/opus/celt/mdct.c b/thirdparty/opus/celt/mdct.c index 5c6dab5b75..5315ad11a3 100644 --- a/thirdparty/opus/celt/mdct.c +++ b/thirdparty/opus/celt/mdct.c @@ -270,8 +270,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca int rev; kiss_fft_scalar yr, yi; rev = *bitrev++; - yr = ADD32_ovflw(S_MUL(*xp2, t[i]), S_MUL(*xp1, t[N4+i])); - yi = SUB32_ovflw(S_MUL(*xp1, t[i]), S_MUL(*xp2, t[N4+i])); + yr = S_MUL(*xp2, t[i]) + S_MUL(*xp1, t[N4+i]); + yi = S_MUL(*xp1, t[i]) - S_MUL(*xp2, t[N4+i]); /* We swap real and imag because we use an FFT instead of an IFFT. */ yp[2*rev+1] = yr; yp[2*rev] = yi; @@ -301,8 +301,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca 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)); + yr = S_MUL(re,t0) + S_MUL(im,t1); + yi = 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]; @@ -312,8 +312,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca 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)); + 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; @@ -333,8 +333,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca 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)); + *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1); + *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1); wp1++; wp2--; } diff --git a/thirdparty/opus/celt/mips/celt_mipsr1.h b/thirdparty/opus/celt/mips/celt_mipsr1.h index c332fe0471..e85661a661 100644 --- a/thirdparty/opus/celt/mips/celt_mipsr1.h +++ b/thirdparty/opus/celt/mips/celt_mipsr1.h @@ -53,7 +53,6 @@ #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, diff --git a/thirdparty/opus/celt/mips/vq_mipsr1.h b/thirdparty/opus/celt/mips/vq_mipsr1.h index f26a33e755..54cef86133 100644 --- a/thirdparty/opus/celt/mips/vq_mipsr1.h +++ b/thirdparty/opus/celt/mips/vq_mipsr1.h @@ -36,6 +36,11 @@ #include "mathops.h" #include "arch.h" +static unsigned extract_collapse_mask(int *iy, int N, int B); +static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X, int N, opus_val32 Ryy, opus_val16 gain); +static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread); +static void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch); + #define OVERRIDE_vq_exp_rotation1 static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) { @@ -64,7 +69,11 @@ static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_ } #define OVERRIDE_renormalise_vector -void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) + +#define renormalise_vector(X, N, gain, arch) \ + (renormalise_vector_mips(X, N, gain, arch)) + +void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch) { int i; #ifdef FIXED_POINT diff --git a/thirdparty/opus/celt/modes.c b/thirdparty/opus/celt/modes.c index 390c5e8aeb..911686e905 100644 --- a/thirdparty/opus/celt/modes.c +++ b/thirdparty/opus/celt/modes.c @@ -427,7 +427,7 @@ void opus_custom_mode_destroy(CELTMode *mode) } #endif /* CUSTOM_MODES_ONLY */ opus_free((opus_int16*)mode->eBands); - opus_free((unsigned char*)mode->allocVectors); + opus_free((opus_int16*)mode->allocVectors); opus_free((opus_val16*)mode->window); opus_free((opus_int16*)mode->logN); diff --git a/thirdparty/opus/celt/pitch.c b/thirdparty/opus/celt/pitch.c index 872582a48a..bf46e7d562 100644 --- a/thirdparty/opus/celt/pitch.c +++ b/thirdparty/opus/celt/pitch.c @@ -102,9 +102,11 @@ static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, } } -static void celt_fir5(opus_val16 *x, +static void celt_fir5(const opus_val16 *x, const opus_val16 *num, - int N) + opus_val16 *y, + int N, + opus_val16 *mem) { int i; opus_val16 num0, num1, num2, num3, num4; @@ -114,11 +116,11 @@ static void celt_fir5(opus_val16 *x, num2=num[2]; num3=num[3]; num4=num[4]; - mem0=0; - mem1=0; - mem2=0; - mem3=0; - mem4=0; + mem0=mem[0]; + mem1=mem[1]; + mem2=mem[2]; + mem3=mem[3]; + mem4=mem[4]; for (i=0;i<N;i++) { opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT); @@ -132,8 +134,13 @@ static void celt_fir5(opus_val16 *x, mem2 = mem1; mem1 = mem0; mem0 = x[i]; - x[i] = ROUND16(sum, SIG_SHIFT); + y[i] = ROUND16(sum, SIG_SHIFT); } + mem[0]=mem0; + mem[1]=mem1; + mem[2]=mem2; + mem[3]=mem3; + mem[4]=mem4; } @@ -143,7 +150,7 @@ void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x int i; opus_val32 ac[5]; opus_val16 tmp=Q15ONE; - opus_val16 lpc[4]; + opus_val16 lpc[4], mem[5]={0,0,0,0,0}; opus_val16 lpc2[5]; opus_val16 c1 = QCONST16(.8f,15); #ifdef FIXED_POINT @@ -204,7 +211,7 @@ void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x 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); + celt_fir5(x_lp, lpc2, x_lp, len>>1, mem); } /* Pure C implementation. */ @@ -213,8 +220,13 @@ opus_val32 #else void #endif +#if defined(OVERRIDE_PITCH_XCORR) celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch) +#else +celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y, opus_val32 *xcorr, int len, int max_pitch, int arch) +#endif { #if 0 /* This is a simple version of the pitch correlation that should work @@ -249,11 +261,15 @@ celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, opus_val32 maxcorr=1; #endif celt_assert(max_pitch>0); - celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); for (i=0;i<max_pitch-3;i+=4) { opus_val32 sum[4]={0,0,0,0}; +#if defined(OVERRIDE_PITCH_XCORR) + xcorr_kernel_c(_x, _y+i, sum, len); +#else xcorr_kernel(_x, _y+i, sum, len, arch); +#endif xcorr[i]=sum[0]; xcorr[i+1]=sum[1]; xcorr[i+2]=sum[2]; @@ -269,7 +285,11 @@ celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, for (;i<max_pitch;i++) { opus_val32 sum; +#if defined(OVERRIDE_PITCH_XCORR) + sum = celt_inner_prod_c(_x, _y+i, len); +#else sum = celt_inner_prod(_x, _y+i, len, arch); +#endif xcorr[i] = sum; #ifdef FIXED_POINT maxcorr = MAX32(maxcorr, sum); @@ -358,7 +378,7 @@ void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTR for (j=0;j<len>>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); + sum = celt_inner_prod_c(x_lp, y+i, len>>1); #endif xcorr[i] = MAX32(-1, sum); #ifdef FIXED_POINT @@ -404,7 +424,7 @@ static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy sx = celt_ilog2(xx)-14; sy = celt_ilog2(yy)-14; shift = sx + sy; - x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14); + x2y2 = MULT16_16_Q14(VSHR32(xx, sx), VSHR32(yy, sy)); if (shift & 1) { if (x2y2 < 32768) { diff --git a/thirdparty/opus/celt/pitch.h b/thirdparty/opus/celt/pitch.h index e425f56aea..d3503532a0 100644 --- a/thirdparty/opus/celt/pitch.h +++ b/thirdparty/opus/celt/pitch.h @@ -46,7 +46,8 @@ #include "mips/pitch_mipsr1.h" #endif -#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \ + || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) # include "arm/pitch_arm.h" #endif @@ -183,10 +184,17 @@ opus_val32 void #endif celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch); + +#if !defined(OVERRIDE_PITCH_XCORR) +#ifdef FIXED_POINT +opus_val32 +#else +void +#endif +celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y, opus_val32 *xcorr, int len, int max_pitch, int arch); -#ifndef OVERRIDE_PITCH_XCORR -# define celt_pitch_xcorr celt_pitch_xcorr_c #endif #endif diff --git a/thirdparty/opus/celt/quant_bands.c b/thirdparty/opus/celt/quant_bands.c index 39a221eda5..95076e0af2 100644 --- a/thirdparty/opus/celt/quant_bands.c +++ b/thirdparty/opus/celt/quant_bands.c @@ -418,7 +418,6 @@ void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *ol 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); } @@ -457,7 +456,7 @@ void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *ol /* It would be better to express this invariant as a test on C at function entry, but that isn't enough to make the static analyzer happy. */ - celt_sig_assert(c<2); + celt_assert(c<2); tell = ec_tell(dec); if(budget-tell>=15) { @@ -548,15 +547,9 @@ void amp2Log2(const CELTMode *m, int effEnd, int end, c=0; do { for (i=0;i<effEnd;i++) - { bandLogE[i+c*m->nbEBands] = - celt_log2(bandE[i+c*m->nbEBands]) + celt_log2(SHL32(bandE[i+c*m->nbEBands],2)) - 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;i<end;i++) bandLogE[c*m->nbEBands+i] = -QCONST16(14.f,DB_SHIFT); } while (++c < C); diff --git a/thirdparty/opus/celt/rate.c b/thirdparty/opus/celt/rate.c index 465e1ba26c..7dfa5be8a6 100644 --- a/thirdparty/opus/celt/rate.c +++ b/thirdparty/opus/celt/rate.c @@ -348,17 +348,12 @@ static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, /*This if() block is the only part of the allocation function that is not a mandatory part of the bitstream: any bands we choose to skip here must be explicitly signaled.*/ - int depth_threshold; - /*We choose a threshold with some hysteresis to keep bands from - fluctuating in and out, but we try not to fold below a certain point. */ - if (codedBands > 17) - depth_threshold = j<prev ? 7 : 9; - else - depth_threshold = 0; + /*Choose a threshold with some hysteresis to keep bands from + fluctuating in and out.*/ #ifdef FUZZING if ((rand()&0x1) == 0) #else - if (codedBands<=start+2 || (band_bits > (depth_threshold*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth)) + if (codedBands<=start+2 || (band_bits > ((j<prev?7:9)*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth)) #endif { ec_enc_bit_logp(ec, 1, 1); @@ -529,7 +524,7 @@ static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, return codedBands; } -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, +int 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) { int lo, hi, len, j; diff --git a/thirdparty/opus/celt/rate.h b/thirdparty/opus/celt/rate.h index fad5e412da..515f7687ce 100644 --- a/thirdparty/opus/celt/rate.h +++ b/thirdparty/opus/celt/rate.h @@ -95,7 +95,7 @@ static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int puls @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, +int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero, 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/thirdparty/opus/celt/static_modes_fixed_arm_ne10.h b/thirdparty/opus/celt/static_modes_fixed_arm_ne10.h index 7623092192..b8ef0cee98 100644 --- a/thirdparty/opus/celt/static_modes_fixed_arm_ne10.h +++ b/thirdparty/opus/celt/static_modes_fixed_arm_ne10.h @@ -1,7 +1,7 @@ /* 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 <NE10_types.h> +#include <NE10_init.h> #ifndef NE10_FFT_PARAMS48000_960 #define NE10_FFT_PARAMS48000_960 diff --git a/thirdparty/opus/celt/static_modes_float_arm_ne10.h b/thirdparty/opus/celt/static_modes_float_arm_ne10.h index 66e1abb101..934a82a420 100644 --- a/thirdparty/opus/celt/static_modes_float_arm_ne10.h +++ b/thirdparty/opus/celt/static_modes_float_arm_ne10.h @@ -1,7 +1,7 @@ /* 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 <NE10_types.h> +#include <NE10_init.h> #ifndef NE10_FFT_PARAMS48000_960 #define NE10_FFT_PARAMS48000_960 diff --git a/thirdparty/opus/celt/tests/test_unit_cwrs32.c b/thirdparty/opus/celt/tests/test_unit_cwrs32.c new file mode 100644 index 0000000000..36dd8af5f5 --- /dev/null +++ b/thirdparty/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 <stdio.h> +#include <string.h> + +#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;t<NDIMS;t++){ + int pseudo; + n=pn[t]; + for(pseudo=1;pseudo<41;pseudo++) + { + int k; +#if defined(SMALL_FOOTPRINT) + opus_uint32 uu[KMAX+2U]; +#endif + opus_uint32 inc; + opus_uint32 nc; + opus_uint32 i; + k=get_pulses(pseudo); + if (k>pkmax[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<nc;i+=inc){ +#if defined(SMALL_FOOTPRINT) + opus_uint32 u[KMAX+2U]; +#endif + int y[NMAX]; + int sy; + opus_uint32 v; + opus_uint32 ii; + int j; +#if defined(SMALL_FOOTPRINT) + memcpy(u,uu,(k+2U)*sizeof(*u)); + cwrsi(n,k,i,y,u); +#else + cwrsi(n,k,i,y); +#endif + sy=0; + for(j=0;j<n;j++)sy+=abs(y[j]); + if(sy!=k){ + fprintf(stderr,"N=%d Pulse count mismatch in cwrsi (%d!=%d).\n", + n,sy,k); + return 99; + } + /*printf("%6u of %u:",i,nc); + for(j=0;j<n;j++)printf(" %+3i",y[j]); + printf(" ->");*/ +#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/thirdparty/opus/celt/tests/test_unit_dft.c b/thirdparty/opus/celt/tests/test_unit_dft.c new file mode 100644 index 0000000000..6166eb0e4f --- /dev/null +++ b/thirdparty/opus/celt/tests/test_unit_dft.c @@ -0,0 +1,189 @@ +/* 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 + +#define SKIP_CONFIG_H + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#include <stdio.h> + +#define CELT_C +#define TEST_UNIT_DFT_C +#include "stack_alloc.h" +#include "kiss_fft.h" +#include "kiss_fft.c" +#include "mathops.c" +#include "entcode.c" + +#if defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1) +# include "x86/x86cpu.c" +#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/armcpu.c" +# include "celt_lpc.c" +# include "pitch.c" +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/celt_neon_intr.c" +# if defined(HAVE_ARM_NE10) +# include "mdct.c" +# include "arm/celt_ne10_fft.c" +# include "arm/celt_ne10_mdct.c" +# endif +# endif +# include "arm/arm_celt_map.c" +#endif + +#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;bin<nfft;++bin) { + double ansr = 0; + double ansi = 0; + double difr; + double difi; + + for (k=0;k<nfft;++k) { + double phase = -2*M_PI*bin*k/nfft; + double re = cos(phase); + double im = sin(phase); + if (isinverse) + im = -im; + + if (!isinverse) + { + re /= nfft; + im /= nfft; + } + + ansr += in[k].r * re - in[k].i * im; + ansi += in[k].r * im + in[k].i * re; + } + /*printf ("%d %d ", (int)ansr, (int)ansi);*/ + difr = ansr - out[bin].r; + difi = ansi - out[bin].i; + errpow += difr*difr + difi*difi; + sigpow += ansr*ansr+ansi*ansi; + } + snr = 10*log10(sigpow/errpow); + printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr ); + if (snr<60) { + printf( "** poor snr: %f ** \n", snr); + ret = 1; + } +} + +void test1d(int nfft,int isinverse,int arch) +{ + size_t buflen = sizeof(kiss_fft_cpx)*nfft; + + kiss_fft_cpx * in = (kiss_fft_cpx*)malloc(buflen); + kiss_fft_cpx * out= (kiss_fft_cpx*)malloc(buflen); + kiss_fft_state *cfg = opus_fft_alloc(nfft,0,0,arch); + int k; + + for (k=0;k<nfft;++k) { + in[k].r = (rand() % 32767) - 16384; + in[k].i = (rand() % 32767) - 16384; + } + + for (k=0;k<nfft;++k) { + in[k].r *= 32768; + in[k].i *= 32768; + } + + if (isinverse) + { + for (k=0;k<nfft;++k) { + in[k].r /= nfft; + in[k].i /= nfft; + } + } + + /*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/ + + if (isinverse) + opus_ifft(cfg,in,out, arch); + else + opus_fft(cfg,in,out, arch); + + /*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/ + + check(in,out,nfft,isinverse); + + free(in); + free(out); + opus_fft_free(cfg, arch); +} + +int main(int argc,char ** argv) +{ + ALLOC_STACK; + int arch = opus_select_arch(); + + if (argc>1) { + int k; + for (k=1;k<argc;++k) { + test1d(atoi(argv[k]),0,arch); + test1d(atoi(argv[k]),1,arch); + } + }else{ + test1d(32,0,arch); + test1d(32,1,arch); + test1d(128,0,arch); + test1d(128,1,arch); + test1d(256,0,arch); + test1d(256,1,arch); +#ifndef RADIX_TWO_ONLY + test1d(36,0,arch); + test1d(36,1,arch); + test1d(50,0,arch); + test1d(50,1,arch); + test1d(60,0,arch); + test1d(60,1,arch); + test1d(120,0,arch); + test1d(120,1,arch); + test1d(240,0,arch); + test1d(240,1,arch); + test1d(480,0,arch); + test1d(480,1,arch); +#endif + } + return ret; +} diff --git a/thirdparty/opus/celt/tests/test_unit_entropy.c b/thirdparty/opus/celt/tests/test_unit_entropy.c new file mode 100644 index 0000000000..ff9265864c --- /dev/null +++ b/thirdparty/opus/celt/tests/test_unit_entropy.c @@ -0,0 +1,382 @@ +/* Copyright (c) 2007-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 <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <time.h> +#include "entcode.h" +#include "entenc.h" +#include "entdec.h" +#include <string.h> + +#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 [<seed>]\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<ft;i++){ + entropy+=log(ft)*M_LOG2E; + ec_enc_uint(&enc,i,ft); + } + } + /*Testing encoding of raw bit values.*/ + for(ftb=1;ftb<16;ftb++){ + for(i=0;i<(1<<ftb);i++){ + entropy+=ftb; + nbits=ec_tell(&enc); + ec_enc_bits(&enc,i,ftb); + nbits2=ec_tell(&enc); + if(nbits2-nbits!=ftb){ + fprintf(stderr,"Used %li bits to encode %i bits directly.\n", + nbits2-nbits,ftb); + ret=-1; + } + } + } + nbits=ec_tell_frac(&enc); + ec_enc_done(&enc); + fprintf(stderr, + "Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n", + entropy,ldexp(nbits,-3),100*(nbits-ldexp(entropy,3))/nbits); + fprintf(stderr,"Packed to %li bytes.\n",(long)ec_range_bytes(&enc)); + ec_dec_init(&dec,ptr,DATA_SIZE); + for(ft=2;ft<1024;ft++){ + for(i=0;i<ft;i++){ + sym=ec_dec_uint(&dec,ft); + if(sym!=(unsigned)i){ + fprintf(stderr,"Decoded %i instead of %i with ft of %i.\n",sym,i,ft); + ret=-1; + } + } + } + for(ftb=1;ftb<16;ftb++){ + for(i=0;i<(1<<ftb);i++){ + sym=ec_dec_bits(&dec,ftb); + if(sym!=(unsigned)i){ + fprintf(stderr,"Decoded %i instead of %i with ftb of %i.\n",sym,i,ftb); + ret=-1; + } + } + } + nbits2=ec_tell_frac(&dec); + if(nbits!=nbits2){ + fprintf(stderr, + "Reported number of bits used was %0.2lf, should be %0.2lf.\n", + ldexp(nbits2,-3),ldexp(nbits,-3)); + ret=-1; + } + /*Testing an encoder bust prefers range coder data over raw bits. + This isn't a general guarantee, will only work for data that is buffered in + the encoder state and not yet stored in the user buffer, and should never + get used in practice. + It's mostly here for code coverage completeness.*/ + /*Start with a 16-bit buffer.*/ + ec_enc_init(&enc,ptr,2); + /*Write 7 raw bits.*/ + ec_enc_bits(&enc,0x55,7); + /*Write 12.3 bits of range coder data.*/ + ec_enc_uint(&enc,1,2); + ec_enc_uint(&enc,1,3); + ec_enc_uint(&enc,1,4); + ec_enc_uint(&enc,1,5); + ec_enc_uint(&enc,2,6); + ec_enc_uint(&enc,6,7); + ec_enc_done(&enc); + ec_dec_init(&dec,ptr,2); + if(!enc.error + /*The raw bits should have been overwritten by the range coder data.*/ + ||ec_dec_bits(&dec,7)!=0x05 + /*And all the range coder data should have been encoded correctly.*/ + ||ec_dec_uint(&dec,2)!=1 + ||ec_dec_uint(&dec,3)!=1 + ||ec_dec_uint(&dec,4)!=1 + ||ec_dec_uint(&dec,5)!=1 + ||ec_dec_uint(&dec,6)!=2 + ||ec_dec_uint(&dec,7)!=6){ + fprintf(stderr,"Encoder bust overwrote range coder data with raw bits.\n"); + ret=-1; + } + srand(seed); + fprintf(stderr,"Testing random streams... Random seed: %u (%.4X)\n", seed, rand() % 65536); + for(i=0;i<409600;i++){ + unsigned *data; + unsigned *tell; + unsigned tell_bits; + int j; + int zeros; + ft=rand()/((RAND_MAX>>(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<sz;j++){ + if (zeros) + data[j]=0; + else + data[j]=rand()%ft; + ec_enc_uint(&enc,data[j],ft); + tell[j+1]=ec_tell_frac(&enc); + } + if (rand()%2==0) + while(ec_tell(&enc)%8 != 0) + ec_enc_uint(&enc, rand()%2, 2); + tell_bits = ec_tell(&enc); + ec_enc_done(&enc); + if(tell_bits!=(unsigned)ec_tell(&enc)){ + fprintf(stderr,"ec_tell() changed after ec_enc_done(): %i instead of %i (Random seed: %u)\n", + ec_tell(&enc),tell_bits,seed); + ret=-1; + } + if ((tell_bits+7)/8 < ec_range_bytes(&enc)) + { + fprintf (stderr, "ec_tell() lied, there's %i bytes instead of %d (Random seed: %u)\n", + ec_range_bytes(&enc), (tell_bits+7)/8,seed); + ret=-1; + } + ec_dec_init(&dec,ptr,DATA_SIZE2); + if(ec_tell_frac(&dec)!=tell[0]){ + fprintf(stderr, + "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", + 0,ec_tell_frac(&dec),tell[0],seed); + } + for(j=0;j<sz;j++){ + sym=ec_dec_uint(&dec,ft); + if(sym!=data[j]){ + fprintf(stderr, + "Decoded %i instead of %i with ft of %i at position %i of %i (Random seed: %u).\n", + sym,data[j],ft,j,sz,seed); + ret=-1; + } + if(ec_tell_frac(&dec)!=tell[j+1]){ + fprintf(stderr, + "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", + j+1,ec_tell_frac(&dec),tell[j+1],seed); + } + } + free(tell); + free(data); + } + /*Test compatibility between multiple different encode/decode routines.*/ + for(i=0;i<409600;i++){ + unsigned *logp1; + unsigned *data; + unsigned *tell; + unsigned *enc_method; + int j; + sz=rand()/((RAND_MAX>>(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<sz;j++){ + data[j]=rand()/((RAND_MAX>>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<<logp1[j])-1:0, + (1<<logp1[j])-(data[j]?0:1),1<<logp1[j]); + }break; + case 1:{ + ec_encode_bin(&enc,data[j]?(1<<logp1[j])-1:0, + (1<<logp1[j])-(data[j]?0:1),logp1[j]); + }break; + case 2:{ + ec_enc_bit_logp(&enc,data[j],logp1[j]); + }break; + case 3:{ + unsigned char icdf[2]; + icdf[0]=1; + icdf[1]=0; + ec_enc_icdf(&enc,data[j],icdf,logp1[j]); + }break; + } + tell[j+1]=ec_tell_frac(&enc); + } + ec_enc_done(&enc); + if((ec_tell(&enc)+7U)/8U<ec_range_bytes(&enc)){ + fprintf(stderr,"tell() lied, there's %i bytes instead of %d (Random seed: %u)\n", + ec_range_bytes(&enc),(ec_tell(&enc)+7)/8,seed); + ret=-1; + } + ec_dec_init(&dec,ptr,DATA_SIZE2); + if(ec_tell_frac(&dec)!=tell[0]){ + fprintf(stderr, + "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", + 0,ec_tell_frac(&dec),tell[0],seed); + } + for(j=0;j<sz;j++){ + int fs; + int dec_method; + dec_method=rand()/((RAND_MAX>>2)+1); + switch(dec_method){ + case 0:{ + fs=ec_decode(&dec,1<<logp1[j]); + sym=fs>=(1<<logp1[j])-1; + ec_dec_update(&dec,sym?(1<<logp1[j])-1:0, + (1<<logp1[j])-(sym?0:1),1<<logp1[j]); + }break; + case 1:{ + fs=ec_decode_bin(&dec,logp1[j]); + sym=fs>=(1<<logp1[j])-1; + ec_dec_update(&dec,sym?(1<<logp1[j])-1:0, + (1<<logp1[j])-(sym?0:1),1<<logp1[j]); + }break; + case 2:{ + sym=ec_dec_bit_logp(&dec,logp1[j]); + }break; + case 3:{ + unsigned char icdf[2]; + icdf[0]=1; + icdf[1]=0; + sym=ec_dec_icdf(&dec,icdf,logp1[j]); + }break; + } + if(sym!=data[j]){ + fprintf(stderr, + "Decoded %i instead of %i with logp1 of %i at position %i of %i (Random seed: %u).\n", + sym,data[j],logp1[j],j,sz,seed); + fprintf(stderr,"Encoding method: %i, decoding method: %i\n", + enc_method[j],dec_method); + ret=-1; + } + if(ec_tell_frac(&dec)!=tell[j+1]){ + fprintf(stderr, + "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n", + j+1,ec_tell_frac(&dec),tell[j+1],seed); + } + } + free(enc_method); + free(tell); + free(data); + free(logp1); + } + ec_enc_init(&enc,ptr,DATA_SIZE2); + ec_enc_bit_logp(&enc,0,1); + ec_enc_bit_logp(&enc,0,1); + ec_enc_bit_logp(&enc,0,1); + ec_enc_bit_logp(&enc,0,1); + ec_enc_bit_logp(&enc,0,2); + ec_enc_patch_initial_bits(&enc,3,2); + if(enc.error){ + fprintf(stderr,"patch_initial_bits failed"); + ret=-1; + } + ec_enc_patch_initial_bits(&enc,0,5); + if(!enc.error){ + fprintf(stderr,"patch_initial_bits didn't fail when it should have"); + ret=-1; + } + ec_enc_done(&enc); + if(ec_range_bytes(&enc)!=1||ptr[0]!=192){ + fprintf(stderr,"Got %d when expecting 192 for patch_initial_bits",ptr[0]); + ret=-1; + } + ec_enc_init(&enc,ptr,DATA_SIZE2); + ec_enc_bit_logp(&enc,0,1); + ec_enc_bit_logp(&enc,0,1); + ec_enc_bit_logp(&enc,1,6); + ec_enc_bit_logp(&enc,0,2); + ec_enc_patch_initial_bits(&enc,0,2); + if(enc.error){ + fprintf(stderr,"patch_initial_bits failed"); + ret=-1; + } + ec_enc_done(&enc); + if(ec_range_bytes(&enc)!=2||ptr[0]!=63){ + fprintf(stderr,"Got %d when expecting 63 for patch_initial_bits",ptr[0]); + ret=-1; + } + ec_enc_init(&enc,ptr,2); + ec_enc_bit_logp(&enc,0,2); + for(i=0;i<48;i++){ + ec_enc_bits(&enc,0,1); + } + ec_enc_done(&enc); + if(!enc.error){ + fprintf(stderr,"Raw bits overfill didn't fail when it should have"); + ret=-1; + } + ec_enc_init(&enc,ptr,2); + for(i=0;i<17;i++){ + ec_enc_bits(&enc,0,1); + } + ec_enc_done(&enc); + if(!enc.error){ + fprintf(stderr,"17 raw bits encoded in two bytes"); + ret=-1; + } + free(ptr); + return ret; +} diff --git a/thirdparty/opus/celt/tests/test_unit_laplace.c b/thirdparty/opus/celt/tests/test_unit_laplace.c new file mode 100644 index 0000000000..22951e29ee --- /dev/null +++ b/thirdparty/opus/celt/tests/test_unit_laplace.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation + Written by Jean-Marc Valin 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 <stdio.h> +#include <stdlib.h> +#include "laplace.h" +#define CELT_C +#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/thirdparty/opus/celt/tests/test_unit_mathops.c b/thirdparty/opus/celt/tests/test_unit_mathops.c new file mode 100644 index 0000000000..fd3319da91 --- /dev/null +++ b/thirdparty/opus/celt/tests/test_unit_mathops.c @@ -0,0 +1,304 @@ +/* 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 + +#define CELT_C + +#include <stdio.h> +#include <math.h> +#include "mathops.c" +#include "entenc.c" +#include "entdec.c" +#include "entcode.c" +#include "bands.c" +#include "quant_bands.c" +#include "laplace.c" +#include "vq.c" +#include "cwrs.c" +#include "pitch.c" +#include "celt_lpc.c" +#include "celt.c" + +#if defined(OPUS_X86_MAY_HAVE_SSE) || defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1) +# if defined(OPUS_X86_MAY_HAVE_SSE) +# include "x86/pitch_sse.c" +# endif +# if defined(OPUS_X86_MAY_HAVE_SSE2) +# include "x86/pitch_sse2.c" +# endif +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) +# include "x86/pitch_sse4_1.c" +# include "x86/celt_lpc_sse.c" +# endif +# include "x86/x86_celt_map.c" +#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/armcpu.c" +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/celt_neon_intr.c" +# if defined(HAVE_ARM_NE10) +# include "kiss_fft.c" +# include "mdct.c" +# include "arm/celt_ne10_fft.c" +# include "arm/celt_ne10_mdct.c" +# endif +# endif +# include "arm/arm_celt_map.c" +#endif + +#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 (d<min_d)min_d=d; + last = q; + } + if ((chk!=89408644)||(max_d!=5)||(min_d!=0)||(bitexact_cos(64)!=32767)|| + (bitexact_cos(16320)!=200)||(bitexact_cos(8192)!=23171)) + { + fprintf (stderr, "bitexact_cos failed\n"); + ret = 1; + } +} + +void testbitexactlog2tan(void) +{ + int i,fail; + opus_int32 min_d,max_d,last,chk; + fail=chk=max_d=0; + last=min_d=15059; + for(i=64;i<8193;i++) + { + opus_int32 d; + opus_int32 mid=bitexact_cos(i); + opus_int32 side=bitexact_cos(16384-i); + opus_int32 q=bitexact_log2tan(mid,side); + chk ^= q*i; + d = last - q; + if (q!=-1*bitexact_log2tan(side,mid)) + fail = 1; + if (d>max_d)max_d=d; + if (d<min_d)min_d=d; + last = q; + } + if ((chk!=15821257)||(max_d!=61)||(min_d!=-2)||fail|| + (bitexact_log2tan(32767,200)!=15059)||(bitexact_log2tan(30274,12540)!=2611)|| + (bitexact_log2tan(23171,23171)!=0)) + { + fprintf (stderr, "bitexact_log2tan failed\n"); + ret = 1; + } +} + +#ifndef FIXED_POINT +void testlog2(void) +{ + float x; + for (x=0.001;x<1677700.0;x+=(x/8.0)) + { + float error = fabs((1.442695040888963387*log(x))-celt_log2(x)); + if (error>0.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<<lg; + + if (x<y || (x>>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/thirdparty/opus/celt/tests/test_unit_mdct.c b/thirdparty/opus/celt/tests/test_unit_mdct.c new file mode 100644 index 0000000000..8dbb9caa2e --- /dev/null +++ b/thirdparty/opus/celt/tests/test_unit_mdct.c @@ -0,0 +1,230 @@ +/* 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 + +#define SKIP_CONFIG_H + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#include <stdio.h> + +#define CELT_C +#include "mdct.h" +#include "stack_alloc.h" + +#include "kiss_fft.c" +#include "mdct.c" +#include "mathops.c" +#include "entcode.c" + +#if defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1) +# include "x86/x86cpu.c" +#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/armcpu.c" +# include "pitch.c" +# include "celt_lpc.c" +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/celt_neon_intr.c" +# if defined(HAVE_ARM_NE10) +# include "arm/celt_ne10_fft.c" +# include "arm/celt_ne10_mdct.c" +# endif +# endif +# include "arm/arm_celt_map.c" +#endif + +#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;bin<nfft/2;++bin) { + double ansr = 0; + double difr; + + for (k=0;k<nfft;++k) { + double phase = 2*M_PI*(k+.5+.25*nfft)*(bin+.5)/nfft; + double re = cos(phase); + + re /= nfft/4; + + ansr += in[k] * re; + } + /*printf ("%f %f\n", ansr, out[bin]);*/ + difr = ansr - out[bin]; + errpow += difr*difr; + sigpow += ansr*ansr; + } + snr = 10*log10(sigpow/errpow); + printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr ); + if (snr<60) { + printf( "** poor snr: %f **\n", snr); + ret = 1; + } +} + +void check_inv(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;bin<nfft;++bin) { + double ansr = 0; + double difr; + + for (k=0;k<nfft/2;++k) { + double phase = 2*M_PI*(bin+.5+.25*nfft)*(k+.5)/nfft; + double re = cos(phase); + + /*re *= 2;*/ + + ansr += in[k] * re; + } + /*printf ("%f %f\n", ansr, out[bin]);*/ + difr = ansr - out[bin]; + errpow += difr*difr; + sigpow += ansr*ansr; + } + snr = 10*log10(sigpow/errpow); + printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr ); + if (snr<60) { + printf( "** poor snr: %f **\n", snr); + ret = 1; + } +} + + +void test1d(int nfft,int isinverse,int arch) +{ + mdct_lookup cfg; + size_t buflen = sizeof(kiss_fft_scalar)*nfft; + + kiss_fft_scalar * in = (kiss_fft_scalar*)malloc(buflen); + kiss_fft_scalar * in_copy = (kiss_fft_scalar*)malloc(buflen); + kiss_fft_scalar * out= (kiss_fft_scalar*)malloc(buflen); + opus_val16 * window= (opus_val16*)malloc(sizeof(opus_val16)*nfft/2); + int k; + + clt_mdct_init(&cfg, nfft, 0, arch); + for (k=0;k<nfft;++k) { + in[k] = (rand() % 32768) - 16384; + } + + for (k=0;k<nfft/2;++k) { + window[k] = Q15ONE; + } + for (k=0;k<nfft;++k) { + in[k] *= 32768; + } + + if (isinverse) + { + for (k=0;k<nfft;++k) { + in[k] /= nfft; + } + } + + for (k=0;k<nfft;++k) + in_copy[k] = in[k]; + /*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/ + + if (isinverse) + { + for (k=0;k<nfft;++k) + out[k] = 0; + clt_mdct_backward(&cfg,in,out, window, nfft/2, 0, 1, arch); + /* apply TDAC because clt_mdct_backward() no longer does that */ + for (k=0;k<nfft/4;++k) + out[nfft-k-1] = out[nfft/2+k]; + check_inv(in,out,nfft,isinverse); + } else { + clt_mdct_forward(&cfg,in,out,window, nfft/2, 0, 1, arch); + check(in_copy,out,nfft,isinverse); + } + /*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/ + + + free(in); + free(in_copy); + free(out); + free(window); + clt_mdct_clear(&cfg, arch); +} + +int main(int argc,char ** argv) +{ + ALLOC_STACK; + int arch = opus_select_arch(); + + if (argc>1) { + int k; + for (k=1;k<argc;++k) { + test1d(atoi(argv[k]),0,arch); + test1d(atoi(argv[k]),1,arch); + } + }else{ + test1d(32,0,arch); + test1d(32,1,arch); + test1d(256,0,arch); + test1d(256,1,arch); + test1d(512,0,arch); + test1d(512,1,arch); + test1d(1024,0,arch); + test1d(1024,1,arch); + test1d(2048,0,arch); + test1d(2048,1,arch); +#ifndef RADIX_TWO_ONLY + test1d(36,0,arch); + test1d(36,1,arch); + test1d(40,0,arch); + test1d(40,1,arch); + test1d(60,0,arch); + test1d(60,1,arch); + test1d(120,0,arch); + test1d(120,1,arch); + test1d(240,0,arch); + test1d(240,1,arch); + test1d(480,0,arch); + test1d(480,1,arch); + test1d(960,0,arch); + test1d(960,1,arch); + test1d(1920,0,arch); + test1d(1920,1,arch); +#endif + } + return ret; +} diff --git a/thirdparty/opus/celt/tests/test_unit_rotation.c b/thirdparty/opus/celt/tests/test_unit_rotation.c new file mode 100644 index 0000000000..1080c2085d --- /dev/null +++ b/thirdparty/opus/celt/tests/test_unit_rotation.c @@ -0,0 +1,120 @@ +/* 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 + +#ifndef CUSTOM_MODES +#define CUSTOM_MODES +#endif + +#define CELT_C + +#include <stdio.h> +#include <stdlib.h> +#include "vq.c" +#include "cwrs.c" +#include "entcode.c" +#include "entenc.c" +#include "entdec.c" +#include "mathops.c" +#include "bands.h" +#include "pitch.c" +#include "celt_lpc.c" +#include "celt.c" +#include <math.h> + +#if defined(OPUS_X86_MAY_HAVE_SSE) || defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1) +# if defined(OPUS_X86_MAY_HAVE_SSE) +# include "x86/pitch_sse.c" +# endif +# if defined(OPUS_X86_MAY_HAVE_SSE2) +# include "x86/pitch_sse2.c" +# endif +# if defined(OPUS_X86_MAY_HAVE_SSE4_1) +# include "x86/pitch_sse4_1.c" +# include "x86/celt_lpc_sse.c" +# endif +# include "x86/x86_celt_map.c" +#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/armcpu.c" +# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +# include "arm/celt_neon_intr.c" +# if defined(HAVE_ARM_NE10) +# include "kiss_fft.c" +# include "mdct.c" +# include "arm/celt_ne10_fft.c" +# include "arm/celt_ne10_mdct.c" +# endif +# endif +# include "arm/arm_celt_map.c" +#endif + +#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<N;i++) + x1[i] = x0[i] = rand()%32767-16384; + exp_rotation(x1, N, 1, 1, K, SPREAD_NORMAL); + for (i=0;i<N;i++) + { + err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]); + ener += x0[i]*(double)x0[i]; + } + snr0 = 20*log10(ener/err); + err = ener = 0; + exp_rotation(x1, N, -1, 1, K, SPREAD_NORMAL); + for (i=0;i<N;i++) + { + err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]); + ener += x0[i]*(double)x0[i]; + } + snr = 20*log10(ener/err); + printf ("SNR for size %d (%d pulses) is %f (was %f without inverse)\n", N, K, snr, snr0); + if (snr < 60 || snr0 > 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/thirdparty/opus/celt/arm/armopts.s b/thirdparty/opus/celt/tests/test_unit_types.c index fb9196072a..67a0fb8ed3 100644 --- a/thirdparty/opus/celt/arm/armopts.s +++ b/thirdparty/opus/celt/tests/test_unit_types.c @@ -1,4 +1,5 @@ -/* Copyright (C) 2013 Mozilla Corporation */ +/* 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 @@ -24,14 +25,26 @@ 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 * +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif -; Set the following to 1 if we have ARMv6 media instructions. -OPUS_ARM_MAY_HAVE_MEDIA * +#include "opus_types.h" +#include <stdio.h> -; Set the following to 1 if we have NEON (some ARMv7) -OPUS_ARM_MAY_HAVE_NEON * - -END +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/thirdparty/opus/celt/vq.c b/thirdparty/opus/celt/vq.c index 8011e22548..d29f38fd8e 100644 --- a/thirdparty/opus/celt/vq.c +++ b/thirdparty/opus/celt/vq.c @@ -39,10 +39,6 @@ #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) { @@ -71,7 +67,7 @@ static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_ } #endif /* OVERRIDE_vq_exp_rotation1 */ -void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +static 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; @@ -162,27 +158,42 @@ static unsigned extract_collapse_mask(int *iy, int N, int B) return collapse_mask; } -opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) +unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc +#ifdef RESYNTH + , opus_val16 gain +#endif + ) { VARDECL(celt_norm, y); - VARDECL(int, signx); + VARDECL(int, iy); + VARDECL(opus_val16, signx); int i, j; + opus_val16 s; int pulsesLeft; opus_val32 sum; opus_val32 xy; opus_val16 yy; + unsigned collapse_mask; SAVE_STACK; - (void)arch; + celt_assert2(K>0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + ALLOC(y, N, celt_norm); - ALLOC(signx, N, int); + ALLOC(iy, N, int); + ALLOC(signx, N, opus_val16); + + exp_rotation(X, N, 1, B, K, spread); /* Get rid of the sign */ sum = 0; j=0; do { - signx[j] = X[j]<0; - /* OPT: Make sure the compiler doesn't use a branch on ABS16(). */ - X[j] = ABS16(X[j]); + if (X[j]>0) + signx[j]=1; + else { + signx[j]=-1; + X[j]=-X[j]; + } iy[j] = 0; y[j] = 0; } while (++j<N); @@ -214,12 +225,7 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) while (++j<N); sum = QCONST16(1.f,14); } -#ifdef FIXED_POINT - rcp = EXTRACT16(MULT16_32_Q16(K, celt_rcp(sum))); -#else - /* Using K+e with e < 1 guarantees we cannot get more than K pulses. */ - rcp = EXTRACT16(MULT16_32_Q16(K+0.8f, celt_rcp(sum))); -#endif + rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum))); j=0; do { #ifdef FIXED_POINT /* It's really important to round *towards zero* here */ @@ -234,12 +240,12 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) pulsesLeft -= iy[j]; } while (++j<N); } - celt_sig_assert(pulsesLeft>=0); + celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass"); /* 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); + celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass"); #endif if (pulsesLeft > N+3) { @@ -250,12 +256,12 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) pulsesLeft=0; } + s = 1; for (i=0;i<pulsesLeft;i++) { - opus_val16 Rxy, Ryy; int best_id; - opus_val32 best_num; - opus_val16 best_den; + opus_val32 best_num = -VERY_LARGE16; + opus_val16 best_den = 0; #ifdef FIXED_POINT int rshift; #endif @@ -266,22 +272,9 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) /* The squared magnitude term gets added anyway, so we might as well add it outside the loop */ yy = ADD16(yy, 1); - - /* Calculations for position 0 are out of the loop, in part to reduce - mispredicted branches (since the if condition is usually false) - in the loop. */ - /* Temporary sums of the new pulse(s) */ - Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[0])),rshift)); - /* We're multiplying y[j] by two so we don't have to do it here */ - Ryy = ADD16(yy, y[0]); - - /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that - Rxy is positive because the sign is pre-computed) */ - Rxy = MULT16_16_Q15(Rxy,Rxy); - best_den = Ryy; - best_num = Rxy; - j=1; + j=0; do { + opus_val16 Rxy, Ryy; /* Temporary sums of the new pulse(s) */ Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift)); /* We're multiplying y[j] by two so we don't have to do it here */ @@ -292,11 +285,8 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) Rxy = MULT16_16_Q15(Rxy,Rxy); /* The idea is to check for num/den >= 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))) + /* OPT: Make sure to use conditional moves here */ + if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num)) { best_den = Ryy; best_num = Rxy; @@ -311,47 +301,23 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch) /* Only now that we've made the final choice, update y/iy */ /* Multiplying y[j] by 2 so we don't have to do it everywhere else */ - y[best_id] += 2; + y[best_id] += 2*s; iy[best_id]++; } /* Put the original sign back */ j=0; do { - /*iy[j] = signx[j] ? -iy[j] : iy[j];*/ - /* OPT: The is more likely to be compiled without a branch than the code above - but has the same performance otherwise. */ - iy[j] = (iy[j]^-signx[j]) + signx[j]; + X[j] = MULT16_16(signx[j],X[j]); + if (signx[j] < 0) + iy[j] = -iy[j]; } while (++j<N); - RESTORE_STACK; - return yy; -} - -unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc, - opus_val16 gain, int resynth, int arch) -{ - VARDECL(int, iy); - opus_val16 yy; - unsigned collapse_mask; - SAVE_STACK; - - celt_assert2(K>0, "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); - } +#ifdef RESYNTH + normalise_residual(iy, X, N, yy, gain); + exp_rotation(X, N, -1, B, K, spread); +#endif collapse_mask = extract_collapse_mask(iy, N, B); RESTORE_STACK; @@ -435,7 +401,7 @@ int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int /* 0.63662 = 2/pi */ itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid)); #else - itheta = (int)floor(.5f+16384*0.63662f*fast_atan2f(side,mid)); + itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid)); #endif return itheta; diff --git a/thirdparty/opus/celt/vq.h b/thirdparty/opus/celt/vq.h index 45ec55918e..5cfcbe50ea 100644 --- a/thirdparty/opus/celt/vq.h +++ b/thirdparty/opus/celt/vq.h @@ -37,18 +37,10 @@ #include "entdec.h" #include "modes.h" -#if (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(FIXED_POINT)) -#include "x86/vq_sse.h" +#if defined(MIPSr1_ASM) +#include "mips/vq_mipsr1.h" #endif -void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread); - -opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch); - -#if !defined(OVERRIDE_OP_PVQ_SEARCH) -#define op_pvq_search(x, iy, K, N, arch) \ - (op_pvq_search_c(x, iy, K, N, arch)) -#endif /** Algebraic pulse-vector quantiser. The signal x is replaced by the sum of * the pitch and a combination of pulses such that its norm is still equal @@ -59,8 +51,12 @@ opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch); * @param enc Entropy encoder state * @ret A mask indicating which blocks in the band received pulses */ -unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc, - opus_val16 gain, int resynth, int arch); +unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, + ec_enc *enc +#ifdef RESYNTH + , opus_val16 gain +#endif + ); /** Algebraic pulse decoder * @param X Decoded normalised spectrum (returned) diff --git a/thirdparty/opus/celt/x86/celt_lpc_sse4_1.c b/thirdparty/opus/celt/x86/celt_lpc_sse.c index 5478568849..67e5592acf 100644 --- a/thirdparty/opus/celt/x86/celt_lpc_sse4_1.c +++ b/thirdparty/opus/celt/x86/celt_lpc_sse.c @@ -40,23 +40,65 @@ #if defined(FIXED_POINT) -void celt_fir_sse4_1(const opus_val16 *x, +void celt_fir_sse4_1(const opus_val16 *_x, const opus_val16 *num, - opus_val16 *y, + opus_val16 *_y, int N, int ord, + opus_val16 *mem, int arch) { int i,j; VARDECL(opus_val16, rnum); + VARDECL(opus_val16, x); __m128i vecNoA; opus_int32 noA ; SAVE_STACK; ALLOC(rnum, ord, opus_val16); + ALLOC(x, N+ord, opus_val16); for(i=0;i<ord;i++) rnum[i] = num[ord-i-1]; + for(i=0;i<ord;i++) + x[i] = mem[ord-i-1]; + + for (i=0;i<N-7;i+=8) + { + x[i+ord ]=_x[i ]; + x[i+ord+1]=_x[i+1]; + x[i+ord+2]=_x[i+2]; + x[i+ord+3]=_x[i+3]; + x[i+ord+4]=_x[i+4]; + x[i+ord+5]=_x[i+5]; + x[i+ord+6]=_x[i+6]; + x[i+ord+7]=_x[i+7]; + } + + for (;i<N-3;i+=4) + { + x[i+ord ]=_x[i ]; + x[i+ord+1]=_x[i+1]; + x[i+ord+2]=_x[i+2]; + x[i+ord+3]=_x[i+3]; + } + + for (;i<N;i++) + x[i+ord]=_x[i]; + + for(i=0;i<ord;i++) + mem[i] = _x[N-i-1]; +#ifdef SMALL_FOOTPRINT + for (i=0;i<N;i++) + { + opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT); + for (j=0;j<ord;j++) + { + sum = MAC16_16(sum,rnum[j],x[i+j]); + } + _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT)); + } +#else noA = EXTEND32(1) << SIG_SHIFT >> 1; vecNoA = _mm_set_epi32(noA, noA, noA, noA); @@ -65,24 +107,25 @@ void celt_fir_sse4_1(const opus_val16 *x, opus_val32 sums[4] = {0}; __m128i vecSum, vecX; - xcorr_kernel(rnum, x+i-ord, sums, ord, arch); + xcorr_kernel(rnum, x+i, sums, ord, arch); vecSum = _mm_loadu_si128((__m128i *)sums); vecSum = _mm_add_epi32(vecSum, vecNoA); vecSum = _mm_srai_epi32(vecSum, SIG_SHIFT); - vecX = OP_CVTEPI16_EPI32_M64(x + i); + vecX = OP_CVTEPI16_EPI32_M64(_x + i); vecSum = _mm_add_epi32(vecSum, vecX); vecSum = _mm_packs_epi32(vecSum, vecSum); - _mm_storel_epi64((__m128i *)(y + i), vecSum); + _mm_storel_epi64((__m128i *)(_y + i), vecSum); } for (;i<N;i++) { opus_val32 sum = 0; for (j=0;j<ord;j++) - sum = MAC16_16(sum, rnum[j], x[i+j-ord]); - y[i] = SATURATE16(ADD32(EXTEND32(x[i]), PSHR32(sum, SIG_SHIFT))); + sum = MAC16_16(sum, rnum[j], x[i + j]); + _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT))); } +#endif RESTORE_STACK; } diff --git a/thirdparty/opus/celt/x86/celt_lpc_sse.h b/thirdparty/opus/celt/x86/celt_lpc_sse.h index 7d1ecf7533..c5ec796ed5 100644 --- a/thirdparty/opus/celt/x86/celt_lpc_sse.h +++ b/thirdparty/opus/celt/x86/celt_lpc_sse.h @@ -41,11 +41,12 @@ void celt_fir_sse4_1( opus_val16 *y, int N, int ord, + opus_val16 *mem, int arch); #if defined(OPUS_X86_PRESUME_SSE4_1) -#define celt_fir(x, num, y, N, ord, arch) \ - ((void)arch, celt_fir_sse4_1(x, num, y, N, ord, arch)) +#define celt_fir(x, num, y, N, ord, mem, arch) \ + ((void)arch, celt_fir_sse4_1(x, num, y, N, ord, mem, arch)) #else @@ -55,10 +56,11 @@ extern void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])( opus_val16 *y, int N, int ord, + opus_val16 *mem, int arch); -# define celt_fir(x, num, y, N, ord, arch) \ - ((*CELT_FIR_IMPL[(arch) & OPUS_ARCHMASK])(x, num, y, N, ord, arch)) +# define celt_fir(x, num, y, N, ord, mem, arch) \ + ((*CELT_FIR_IMPL[(arch) & OPUS_ARCHMASK])(x, num, y, N, ord, mem, arch)) #endif #endif diff --git a/thirdparty/opus/celt/x86/vq_sse.h b/thirdparty/opus/celt/x86/vq_sse.h deleted file mode 100644 index b4efe8f249..0000000000 --- a/thirdparty/opus/celt/x86/vq_sse.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2016 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 VQ_SSE_H -#define VQ_SSE_H - -#if defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(FIXED_POINT) -#define OVERRIDE_OP_PVQ_SEARCH - -opus_val16 op_pvq_search_sse2(celt_norm *_X, int *iy, int K, int N, int arch); - -#if defined(OPUS_X86_PRESUME_SSE2) -#define op_pvq_search(x, iy, K, N, arch) \ - (op_pvq_search_sse2(x, iy, K, N, arch)) - -#else - -extern opus_val16 (*const OP_PVQ_SEARCH_IMPL[OPUS_ARCHMASK + 1])( - celt_norm *_X, int *iy, int K, int N, int arch); - -# define op_pvq_search(X, iy, K, N, arch) \ - ((*OP_PVQ_SEARCH_IMPL[(arch) & OPUS_ARCHMASK])(X, iy, K, N, arch)) - -#endif -#endif - -#endif diff --git a/thirdparty/opus/celt/x86/vq_sse2.c b/thirdparty/opus/celt/x86/vq_sse2.c deleted file mode 100644 index 775042860d..0000000000 --- a/thirdparty/opus/celt/x86/vq_sse2.c +++ /dev/null @@ -1,217 +0,0 @@ -/* Copyright (c) 2007-2008 CSIRO - Copyright (c) 2007-2009 Xiph.Org Foundation - Copyright (c) 2007-2016 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 <xmmintrin.h> -#include <emmintrin.h> -#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;j+=4) - { - __m128 x4, s4; - x4 = _mm_loadu_ps(&X[j]); - s4 = _mm_cmplt_ps(x4, _mm_setzero_ps()); - /* Get rid of the sign */ - x4 = _mm_andnot_ps(signmask, x4); - sums = _mm_add_ps(sums, x4); - /* Clear y and iy in case we don't do the projection. */ - _mm_storeu_ps(&y[j], _mm_setzero_ps()); - _mm_storeu_si128((__m128i*)&iy[j], _mm_setzero_si128()); - _mm_storeu_ps(&X[j], x4); - _mm_storeu_ps(&signy[j], s4); - } - sums = _mm_add_ps(sums, _mm_shuffle_ps(sums, sums, _MM_SHUFFLE(1, 0, 3, 2))); - sums = _mm_add_ps(sums, _mm_shuffle_ps(sums, sums, _MM_SHUFFLE(2, 3, 0, 1))); - - xy = yy = 0; - - pulsesLeft = K; - - /* Do a pre-search by projecting on the pyramid */ - if (K > (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<N); - sums = _mm_set_ps1(1.f); - } - /* Using K+e with e < 1 guarantees we cannot get more than K pulses. */ - rcp4 = _mm_mul_ps(_mm_set_ps1((float)(K+.8)), _mm_rcp_ps(sums)); - xy4 = yy4 = _mm_setzero_ps(); - pulses_sum = _mm_setzero_si128(); - for (j=0;j<N;j+=4) - { - __m128 rx4, x4, y4; - __m128i iy4; - x4 = _mm_loadu_ps(&X[j]); - rx4 = _mm_mul_ps(x4, rcp4); - iy4 = _mm_cvttps_epi32(rx4); - pulses_sum = _mm_add_epi32(pulses_sum, iy4); - _mm_storeu_si128((__m128i*)&iy[j], iy4); - y4 = _mm_cvtepi32_ps(iy4); - xy4 = _mm_add_ps(xy4, _mm_mul_ps(x4, y4)); - yy4 = _mm_add_ps(yy4, _mm_mul_ps(y4, y4)); - /* double the y[] vector so we don't have to do it in the search loop. */ - _mm_storeu_ps(&y[j], _mm_add_ps(y4, y4)); - } - pulses_sum = _mm_add_epi32(pulses_sum, _mm_shuffle_epi32(pulses_sum, _MM_SHUFFLE(1, 0, 3, 2))); - pulses_sum = _mm_add_epi32(pulses_sum, _mm_shuffle_epi32(pulses_sum, _MM_SHUFFLE(2, 3, 0, 1))); - pulsesLeft -= _mm_cvtsi128_si32(pulses_sum); - xy4 = _mm_add_ps(xy4, _mm_shuffle_ps(xy4, xy4, _MM_SHUFFLE(1, 0, 3, 2))); - xy4 = _mm_add_ps(xy4, _mm_shuffle_ps(xy4, xy4, _MM_SHUFFLE(2, 3, 0, 1))); - xy = _mm_cvtss_f32(xy4); - yy4 = _mm_add_ps(yy4, _mm_shuffle_ps(yy4, yy4, _MM_SHUFFLE(1, 0, 3, 2))); - yy4 = _mm_add_ps(yy4, _mm_shuffle_ps(yy4, yy4, _MM_SHUFFLE(2, 3, 0, 1))); - yy = _mm_cvtss_f32(yy4); - } - X[N] = X[N+1] = X[N+2] = -100; - y[N] = y[N+1] = y[N+2] = 100; - celt_sig_assert(pulsesLeft>=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<pulsesLeft;i++) - { - int best_id; - __m128 xy4, yy4; - __m128 max, max2; - __m128i count; - __m128i pos; - /* The squared magnitude term gets added anyway, so we might as well - add it outside the loop */ - yy = ADD16(yy, 1); - xy4 = _mm_load1_ps(&xy); - yy4 = _mm_load1_ps(&yy); - max = _mm_setzero_ps(); - pos = _mm_setzero_si128(); - count = _mm_set_epi32(3, 2, 1, 0); - for (j=0;j<N;j+=4) - { - __m128 x4, y4, r4; - x4 = _mm_loadu_ps(&X[j]); - y4 = _mm_loadu_ps(&y[j]); - x4 = _mm_add_ps(x4, xy4); - y4 = _mm_add_ps(y4, yy4); - y4 = _mm_rsqrt_ps(y4); - r4 = _mm_mul_ps(x4, y4); - /* Update the index of the max. */ - pos = _mm_max_epi16(pos, _mm_and_si128(count, _mm_castps_si128(_mm_cmpgt_ps(r4, max)))); - /* Update the max. */ - max = _mm_max_ps(max, r4); - /* Update the indices (+4) */ - count = _mm_add_epi32(count, fours); - } - /* Horizontal max */ - max2 = _mm_max_ps(max, _mm_shuffle_ps(max, max, _MM_SHUFFLE(1, 0, 3, 2))); - max2 = _mm_max_ps(max2, _mm_shuffle_ps(max2, max2, _MM_SHUFFLE(2, 3, 0, 1))); - /* Now that max2 contains the max at all positions, look at which value(s) of the - partial max is equal to the global max. */ - pos = _mm_and_si128(pos, _mm_castps_si128(_mm_cmpeq_ps(max, max2))); - pos = _mm_max_epi16(pos, _mm_unpackhi_epi64(pos, pos)); - pos = _mm_max_epi16(pos, _mm_shufflelo_epi16(pos, _MM_SHUFFLE(1, 0, 3, 2))); - best_id = _mm_cvtsi128_si32(pos); - - /* Updating the sums of the new pulse(s) */ - xy = ADD32(xy, EXTEND32(X[best_id])); - /* We're multiplying y[j] by two so we don't have to do it here */ - yy = ADD16(yy, y[best_id]); - - /* Only now that we've made the final choice, update y/iy */ - /* Multiplying y[j] by 2 so we don't have to do it everywhere else */ - y[best_id] += 2; - iy[best_id]++; - } - - /* Put the original sign back */ - for (j=0;j<N;j+=4) - { - __m128i y4; - __m128i s4; - y4 = _mm_loadu_si128((__m128i*)&iy[j]); - s4 = _mm_castps_si128(_mm_loadu_ps(&signy[j])); - y4 = _mm_xor_si128(_mm_add_epi32(y4, s4), s4); - _mm_storeu_si128((__m128i*)&iy[j], y4); - } - RESTORE_STACK; - return yy; -} - -#endif diff --git a/thirdparty/opus/celt/x86/x86_celt_map.c b/thirdparty/opus/celt/x86/x86_celt_map.c index d39d88edec..47ba41b9ee 100644 --- a/thirdparty/opus/celt/x86/x86_celt_map.c +++ b/thirdparty/opus/celt/x86/x86_celt_map.c @@ -33,7 +33,6 @@ #include "celt_lpc.h" #include "pitch.h" #include "pitch_sse.h" -#include "vq.h" #if defined(OPUS_HAVE_RTCD) @@ -47,6 +46,7 @@ void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])( opus_val16 *y, int N, int ord, + opus_val16 *mem, int arch ) = { celt_fir_c, /* non-sse */ @@ -151,17 +151,5 @@ void (*const COMB_FILTER_CONST_IMPL[OPUS_ARCHMASK + 1])( #endif -#if defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2) -opus_val16 (*const OP_PVQ_SEARCH_IMPL[OPUS_ARCHMASK + 1])( - celt_norm *_X, int *iy, int K, int N, int arch -) = { - op_pvq_search_c, /* non-sse */ - op_pvq_search_c, - MAY_HAVE_SSE2(op_pvq_search), - MAY_HAVE_SSE2(op_pvq_search), - MAY_HAVE_SSE2(op_pvq_search) -}; -#endif - #endif #endif diff --git a/thirdparty/opus/celt/x86/x86cpu.h b/thirdparty/opus/celt/x86/x86cpu.h index 1e2bf17b9b..04fd48aac4 100644 --- a/thirdparty/opus/celt/x86/x86cpu.h +++ b/thirdparty/opus/celt/x86/x86cpu.h @@ -82,9 +82,7 @@ int opus_select_arch(void); (_mm_cvtepi8_epi32(*(__m128i *)(x))) #endif -/* similar reasoning about the instruction sequence as in the 32-bit macro above, - */ -# if defined(__clang__) || !defined(__OPTIMIZE__) +# if !defined(__OPTIMIZE__) # define OP_CVTEPI16_EPI32_M64(x) \ (_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x)))) # else diff --git a/thirdparty/opus/config.h b/thirdparty/opus/config.h index 3ed0874d4b..7b9c92c6a8 100644 --- a/thirdparty/opus/config.h +++ b/thirdparty/opus/config.h @@ -1,44 +1,5 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* Get CPU Info by asm method */ -#define CPU_INFO_BY_ASM 1 - -/* Get CPU Info by c method */ -/* #undef CPU_INFO_BY_C */ - -/* Custom modes */ -/* #undef CUSTOM_MODES */ - -/* Do not build the float API */ -/* #undef DISABLE_FLOAT_API */ - -/* Disable bitstream fixes from RFC 8251 */ -/* #undef DISABLE_UPDATE_DRAFT */ - -/* Assertions */ -/* #undef ENABLE_ASSERTIONS */ - -/* Hardening */ -#define ENABLE_HARDENING 1 - -/* Debug fixed-point implementation */ -/* #undef FIXED_DEBUG */ - -/* Compile as fixed-point (for machines without a fast enough FPU) */ -/* #undef FIXED_POINT */ - -/* Float approximations */ -/* #undef FLOAT_APPROX */ - -/* Fuzzing */ -/* #undef FUZZING */ - -/* Define to 1 if you have the <alloca.h> header file. */ -/* #undef HAVE_ALLOCA_H */ - -/* NE10 library is installed on host. Make sure it is on target! */ -/* #undef HAVE_ARM_NE10 */ +/* Opus configuration header */ +/* Based on the output of libopus configure script */ /* Define to 1 if you have the <dlfcn.h> header file. */ #define HAVE_DLFCN_H 1 @@ -46,12 +7,16 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #define HAVE_INTTYPES_H 1 +#if (!defined( _MSC_VER ) || ( _MSC_VER >= 1800 )) + /* Define to 1 if you have the `lrint' function. */ #define HAVE_LRINT 1 /* Define to 1 if you have the `lrintf' function. */ #define HAVE_LRINTF 1 +#endif + /* Define to 1 if you have the <memory.h> header file. */ #define HAVE_MEMORY_H 1 @@ -76,10 +41,8 @@ /* Define to 1 if you have the <unistd.h> header file. */ #define HAVE_UNISTD_H 1 -/* Define to 1 if you have the `__malloc_hook' function. */ -#define HAVE___MALLOC_HOOK 1 - -/* Define to the sub-directory where libtool stores uninstalled libraries. */ +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ #define LT_OBJDIR ".libs/" #ifdef OPUS_ARM_OPT @@ -129,80 +92,9 @@ #endif // OPUS_ARM64_OPT -/* Define if binary requires Aarch64 Neon Intrinsics */ -/* #undef OPUS_ARM_PRESUME_AARCH64_NEON_INTR */ - -/* Define if binary requires EDSP instruction support */ -/* #undef OPUS_ARM_PRESUME_EDSP */ - -/* Define if binary requires ARMv6 media instruction support */ -/* #undef OPUS_ARM_PRESUME_MEDIA */ - -/* Define if binary requires NEON instruction support */ -/* #undef OPUS_ARM_PRESUME_NEON */ - -/* Define if binary requires NEON intrinsics support */ -/* #undef OPUS_ARM_PRESUME_NEON_INTR */ - /* This is a build of OPUS */ #define OPUS_BUILD /**/ -/* Run bit-exactness checks between optimized and c implementations */ -/* #undef OPUS_CHECK_ASM */ - -#ifndef OPUS_ARM_OPT -/* Use run-time CPU capabilities detection */ -#define OPUS_HAVE_RTCD 1 -#endif - -/* Compiler supports X86 AVX Intrinsics */ -/* #define OPUS_X86_MAY_HAVE_AVX */ - -/* Compiler supports X86 SSE Intrinsics */ -/* #define OPUS_X86_MAY_HAVE_SSE */ - -/* Compiler supports X86 SSE2 Intrinsics */ -/* #define OPUS_X86_MAY_HAVE_SSE2 */ - -/* Compiler supports X86 SSE4.1 Intrinsics */ -/* #define OPUS_X86_MAY_HAVE_SSE4_1 */ - -/* Define if binary requires AVX intrinsics support */ -/* #undef OPUS_X86_PRESUME_AVX */ - -/* Define if binary requires SSE intrinsics support */ -#define OPUS_X86_PRESUME_SSE 1 - -/* Define if binary requires SSE2 intrinsics support */ -#define OPUS_X86_PRESUME_SSE2 1 - -/* Define if binary requires SSE4.1 intrinsics support */ -#define OPUS_X86_PRESUME_SSE4_1 1 - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "opus@xiph.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "opus" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "opus 1.3.1" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "opus" - -/* Define to the home page for this package. */ -#define PACKAGE_URL "" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "1.3.1" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Make use of alloca */ -/* #undef USE_ALLOCA */ - #ifndef WIN32 /* Use C99 variable-size arrays */ #define VAR_ARRAYS 1 @@ -211,13 +103,11 @@ #define USE_ALLOCA 1 #endif -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - #ifndef OPUS_FIXED_POINT #define FLOAT_APPROX 1 #endif + /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus @@ -227,7 +117,11 @@ /* 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. */ +#if (!defined( _MSC_VER ) || ( _MSC_VER >= 1800 )) #define restrict __restrict +#else +#undef restrict +#endif /* 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 diff --git a/thirdparty/opus/info.c b/thirdparty/opus/info.c index 3a1a5bf75b..c36f9a9ee1 100644 --- a/thirdparty/opus/info.c +++ b/thirdparty/opus/info.c @@ -107,32 +107,26 @@ static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){ char **user_comments; int *comment_lengths; int cur_ncomments; + char *binary_suffix_data; + int binary_suffix_len; 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=_tags->comment_lengths; + binary_suffix_len=comment_lengths==NULL?0:comment_lengths[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]; + comment_lengths[_ncomments]=binary_suffix_len; _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=_tags->user_comments; + binary_suffix_data=user_comments==NULL?NULL:user_comments[cur_ncomments]; 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]; + user_comments[_ncomments]=binary_suffix_data; _tags->user_comments=user_comments; return 0; } @@ -281,30 +275,28 @@ int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){ ret=opus_tags_copy_impl(&dst,_src); if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst); else *_dst=*&dst; - return ret; + return 0; } 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; + char *comment; + int tag_len; + int 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<tag_len)return OP_EFAULT; - 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->comment_lengths[ncomments]=tag_len+value_len+1; _tags->comments=ncomments+1; return 0; } @@ -345,10 +337,7 @@ int opus_tags_set_binary_suffix(OpusTags *_tags, } 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); + return opus_tagncompare(_tag_name,strlen(_tag_name),_comment); } int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){ @@ -359,18 +348,17 @@ int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){ } 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; + char **user_comments; + int 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<ncomments;ci++){ - if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci])){ + if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){ /*We return a pointer to the data, not a copy.*/ if(_count==found++)return user_comments[ci]+tag_len+1; } @@ -380,18 +368,17 @@ const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){ } int opus_tags_query_count(const OpusTags *_tags,const char *_tag){ - char **user_comments; - size_t tag_len; - int found; - int ncomments; - int ci; + char **user_comments; + int tag_len; + int found; + int ncomments; + int ci; tag_len=strlen(_tag); - if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return 0; ncomments=_tags->comments; user_comments=_tags->user_comments; found=0; for(ci=0;ci<ncomments;ci++){ - if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci]))found++; + if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++; } return found; } @@ -416,8 +403,7 @@ static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8, ncomments=_tags->comments; /*Look for the first valid tag with the name _tag_name and use that.*/ for(ci=0;ci<ncomments;ci++){ - OP_ASSERT(_tag_len<=(size_t)INT_MAX); - if(opus_tagncompare(_tag_name,(int)_tag_len,comments[ci])==0){ + if(opus_tagncompare(_tag_name,_tag_len,comments[ci])==0){ char *p; opus_int32 gain_q8; int negative; @@ -453,7 +439,8 @@ int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){ } static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){ - return _buf_sz>=3&&memcmp(_buf,"\xFF\xD8\xFF",3)==0; + return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0 + &&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0; } /*Tries to extract the width, height, bits per pixel, and palette size of a diff --git a/thirdparty/opus/internal.h b/thirdparty/opus/internal.h index 9ac17e028f..ee48ea34c9 100644 --- a/thirdparty/opus/internal.h +++ b/thirdparty/opus/internal.h @@ -136,9 +136,6 @@ struct OggOpusLink{ 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; @@ -153,25 +150,23 @@ struct OggOpusLink{ }; struct OggOpusFile{ - /*The callbacks used to access the stream.*/ + /*The callbacks used to access the data source.*/ OpusFileCallbacks callbacks; - /*A FILE *, memory buffer, etc.*/ - void *stream; - /*Whether or not we can seek with this stream.*/ + /*A FILE *, memory bufer, etc.*/ + void *source; + /*Whether or not we can seek with this data source.*/ 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 + If source 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.*/ + /*Storage for the list of serial numbers from a single 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 @@ -179,9 +174,9 @@ struct OggOpusFile{ 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.*/ + /*The total size of this data source, or -1 if it's unseekable.*/ opus_int64 end; - /*Used to locate pages in the stream.*/ + /*Used to locate pages in the data source.*/ ogg_sync_state oy; /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/ int ready_state; @@ -232,7 +227,7 @@ struct OggOpusFile{ /*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.*/ + One of OP_HEADER_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/ int gain_type; /*The offset to apply to the gain.*/ opus_int32 gain_offset_q8; diff --git a/thirdparty/opus/mapping_matrix.c b/thirdparty/opus/mapping_matrix.c deleted file mode 100644 index 31298af057..0000000000 --- a/thirdparty/opus/mapping_matrix.c +++ /dev/null @@ -1,378 +0,0 @@ -/* 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/thirdparty/opus/mapping_matrix.h b/thirdparty/opus/mapping_matrix.h deleted file mode 100644 index 98bc82df3e..0000000000 --- a/thirdparty/opus/mapping_matrix.h +++ /dev/null @@ -1,133 +0,0 @@ -/* 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/thirdparty/opus/mlp.c b/thirdparty/opus/mlp.c index 964c6a98f6..ff9e50df47 100644 --- a/thirdparty/opus/mlp.c +++ b/thirdparty/opus/mlp.c @@ -1,5 +1,5 @@ /* Copyright (c) 2008-2011 Octasic Inc. - 2012-2017 Jean-Marc Valin */ + Written by Jean-Marc Valin */ /* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -29,13 +29,42 @@ #include "config.h" #endif -#include <math.h> #include "opus_types.h" #include "opus_defines.h" + +#include <math.h> +#include "mlp.h" #include "arch.h" #include "tansig_table.h" -#include "mlp.h" +#define MAX_NEURONS 100 +#if 0 +static OPUS_INLINE opus_val16 tansig_approx(opus_val32 _x) /* Q19 */ +{ + int i; + opus_val16 xx; /* Q11 */ + /*double x, y;*/ + opus_val16 dy, yy; /* Q14 */ + /*x = 1.9073e-06*_x;*/ + if (_x>=QCONST32(8,19)) + return QCONST32(1.,14); + if (_x<=-QCONST32(8,19)) + return -QCONST32(1.,14); + xx = EXTRACT16(SHR32(_x, 8)); + /*i = lrint(25*x);*/ + i = SHR32(ADD32(1024,MULT16_16(25, xx)),11); + /*x -= .04*i;*/ + xx -= EXTRACT16(SHR32(MULT16_16(20972,i),8)); + /*x = xx*(1./2048);*/ + /*y = tansig_table[250+i];*/ + yy = tansig_table[250+i]; + /*y = yy*(1./16384);*/ + dy = 16384-MULT16_16_Q14(yy,yy); + yy = yy + MULT16_16_Q14(MULT16_16_Q11(xx,dy),(16384 - MULT16_16_Q11(yy,xx))); + return yy; +} +#else +/*extern const float tansig_table[501];*/ static OPUS_INLINE float tansig_approx(float x) { int i; @@ -63,82 +92,54 @@ static OPUS_INLINE float tansig_approx(float x) y = y + x*dy*(1 - y*x); return sign*y; } +#endif -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;i<rows;i++) - { - for (j=0;j<cols;j++) - out[i] += weights[j*col_stride + i]*x[j]; - } -} - -void compute_dense(const DenseLayer *layer, float *output, const float *input) +#if 0 +void mlp_process(const MLP *m, const opus_val16 *in, opus_val16 *out) { - int i; - int N, M; - int stride; - M = layer->nb_inputs; - N = layer->nb_neurons; - stride = N; - for (i=0;i<N;i++) - output[i] = layer->bias[i]; - gemm_accum(output, layer->input_weights, N, M, stride, input); - for (i=0;i<N;i++) - output[i] *= WEIGHTS_SCALE; - if (layer->sigmoid) { - for (i=0;i<N;i++) - output[i] = sigmoid_approx(output[i]); - } else { - for (i=0;i<N;i++) - output[i] = tansig_approx(output[i]); - } + int j; + opus_val16 hidden[MAX_NEURONS]; + const opus_val16 *W = m->weights; + /* Copy to tmp_in */ + for (j=0;j<m->topo[1];j++) + { + int k; + opus_val32 sum = SHL32(EXTEND32(*W++),8); + for (k=0;k<m->topo[0];k++) + sum = MAC16_16(sum, in[k],*W++); + hidden[j] = tansig_approx(sum); + } + for (j=0;j<m->topo[2];j++) + { + int k; + opus_val32 sum = SHL32(EXTEND32(*W++),14); + for (k=0;k<m->topo[1];k++) + sum = MAC16_16(sum, hidden[k], *W++); + out[j] = tansig_approx(EXTRACT16(PSHR32(sum,17))); + } } - -void compute_gru(const GRULayer *gru, float *state, const float *input) +#else +void mlp_process(const MLP *m, const float *in, float *out) { - int i; - int N, M; - int stride; - float tmp[MAX_NEURONS]; - float z[MAX_NEURONS]; - float r[MAX_NEURONS]; - float h[MAX_NEURONS]; - M = gru->nb_inputs; - N = gru->nb_neurons; - stride = 3*N; - /* Compute update gate. */ - for (i=0;i<N;i++) - z[i] = gru->bias[i]; - gemm_accum(z, gru->input_weights, N, M, stride, input); - gemm_accum(z, gru->recurrent_weights, N, N, stride, state); - for (i=0;i<N;i++) - z[i] = sigmoid_approx(WEIGHTS_SCALE*z[i]); - - /* Compute reset gate. */ - for (i=0;i<N;i++) - r[i] = gru->bias[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;i<N;i++) - r[i] = sigmoid_approx(WEIGHTS_SCALE*r[i]); - - /* Compute output. */ - for (i=0;i<N;i++) - h[i] = gru->bias[2*N + i]; - for (i=0;i<N;i++) - tmp[i] = state[i] * r[i]; - gemm_accum(h, &gru->input_weights[2*N], N, M, stride, input); - gemm_accum(h, &gru->recurrent_weights[2*N], N, N, stride, tmp); - for (i=0;i<N;i++) - h[i] = z[i]*state[i] + (1-z[i])*tansig_approx(WEIGHTS_SCALE*h[i]); - for (i=0;i<N;i++) - state[i] = h[i]; + int j; + float hidden[MAX_NEURONS]; + const float *W = m->weights; + /* Copy to tmp_in */ + for (j=0;j<m->topo[1];j++) + { + int k; + float sum = *W++; + for (k=0;k<m->topo[0];k++) + sum = sum + in[k]**W++; + hidden[j] = tansig_approx(sum); + } + for (j=0;j<m->topo[2];j++) + { + int k; + float sum = *W++; + for (k=0;k<m->topo[1];k++) + sum = sum + hidden[k]**W++; + out[j] = tansig_approx(sum); + } } - +#endif diff --git a/thirdparty/opus/mlp.h b/thirdparty/opus/mlp.h index d7670550fd..618e246e2c 100644 --- a/thirdparty/opus/mlp.h +++ b/thirdparty/opus/mlp.h @@ -1,4 +1,5 @@ -/* Copyright (c) 2017 Jean-Marc Valin */ +/* Copyright (c) 2008-2011 Octasic Inc. + Written by Jean-Marc Valin */ /* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -27,34 +28,16 @@ #ifndef _MLP_H_ #define _MLP_H_ -#include "opus_types.h" - -#define WEIGHTS_SCALE (1.f/128) - -#define MAX_NEURONS 32 +#include "arch.h" typedef struct { - const opus_int8 *bias; - const opus_int8 *input_weights; - int nb_inputs; - int nb_neurons; - int sigmoid; -} DenseLayer; - -typedef struct { - const opus_int8 *bias; - const opus_int8 *input_weights; - const opus_int8 *recurrent_weights; - int nb_inputs; - int nb_neurons; -} GRULayer; - -extern const DenseLayer layer0; -extern const GRULayer layer1; -extern const DenseLayer layer2; + int layers; + const int *topo; + const float *weights; +} MLP; -void compute_dense(const DenseLayer *layer, float *output, const float *input); +extern const MLP net; -void compute_gru(const GRULayer *gru, float *state, const float *input); +void mlp_process(const MLP *m, const float *in, float *out); #endif /* _MLP_H_ */ diff --git a/thirdparty/opus/mlp_data.c b/thirdparty/opus/mlp_data.c index ae4178df76..c2fda4e2e5 100644 --- a/thirdparty/opus/mlp_data.c +++ b/thirdparty/opus/mlp_data.c @@ -1,4 +1,5 @@ -/*This file is automatically generated from a Keras model*/ +/* The contents of this file was automatically generated by mlp_train.c + It contains multi-layer perceptron (MLP) weights. */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -6,667 +7,103 @@ #include "mlp.h" -static const opus_int8 layer0_weights[800] = { - -30, -9, 2, -12, 5, -1, 8, 9, - 9, 8, -13, 18, -17, -34, -5, 17, - -11, 0, -4, 10, 2, 10, 15, -8, - 2, -1, 0, 5, 13, -3, -16, 1, - -5, 3, 7, -28, -13, 6, 36, -3, - 19, -60, -17, -28, 7, -11, -30, -7, - 2, -42, -21, -3, 6, -22, 33, -9, - 7, -30, 21, -14, 24, -11, -20, -18, - -5, -12, 12, -49, -50, -49, 16, 9, - -37, -1, 9, 34, -13, -31, -31, 12, - 16, 44, -42, 2, -9, 8, -18, -6, - 9, 36, 19, 11, 13, 12, -21, 3, - -28, -12, 3, 33, 25, -14, 11, 1, - -94, -39, 18, -12, -11, -15, -7, 49, - 52, 10, -43, 9, 57, 8, 21, -6, - 14, -15, 44, -8, 7, -30, -13, -2, - -9, 25, -2, -127, 18, -11, -52, 26, - -27, 27, 10, -10, 7, 43, 6, -24, - 41, 10, -18, -27, 10, 17, 9, 10, - -17, -10, 20, -6, 22, 55, 35, -80, - 36, 25, -24, -36, 15, 9, -19, 88, - 19, 64, -51, -35, 17, 0, -7, 41, - -16, 27, 4, 15, -1, 18, -16, 47, - -39, -54, -8, 13, -25, -20, 102, -18, - -5, 44, 11, -28, 71, 2, -51, -5, - 5, 2, -83, -9, -29, 8, 21, -53, - 58, -37, -7, 13, 38, 9, 34, -1, - -41, 21, 4, -24, -36, -33, -21, 32, - 75, -2, 1, -68, -1, 47, -29, 32, - 20, 12, -65, -87, 5, 16, -12, 24, - 40, 15, 7, 19, -26, -17, 17, 6, - -2, -37, -30, -9, 32, -127, -39, 0, - -31, -27, 4, -22, 23, -6, -77, 35, - -61, 32, -37, -24, 13, -11, -1, -40, - -3, 17, -7, 13, 11, 59, -19, 10, - 6, -18, 0, 13, 3, -6, -23, 19, - 11, -17, 13, -1, -80, 40, -53, 69, - -29, -54, 0, -4, 33, -25, -2, 38, - 35, 36, -15, 46, 2, -13, -16, -8, - -8, 12, -24, -9, -55, -5, -9, 32, - 11, 7, 12, -18, -10, -86, -38, 54, - 37, -25, 18, -43, 7, -27, -27, -54, - 13, 9, 22, 70, 6, 35, -7, 23, - -15, -44, -6, 7, -66, -85, 32, 40, - -19, -9, -7, 12, -15, 7, 2, 6, - -35, 11, 28, 0, 26, 14, 1, 1, - 4, 12, 18, 35, 22, -18, -3, 14, - -1, 7, 14, -8, -14, -3, 4, -3, - -19, -7, -1, -25, -27, 25, -26, -2, - 33, -22, -27, -25, 4, -9, 7, 21, - 26, -30, 10, -9, -20, 11, 27, 10, - 5, -18, 14, -4, 2, -17, -5, -7, - -9, -13, 15, 29, 1, -10, -16, -10, - 35, 36, -7, -22, -44, 17, 30, 22, - 21, -1, 22, -11, 32, -8, -7, 5, - -10, 5, 30, -20, 29, -20, -34, 12, - -4, -6, 6, -13, 10, -5, -68, -1, - 24, 9, 19, -24, -64, 31, 19, 27, - -26, 75, -45, 41, 39, -42, 8, 6, - 23, -30, 16, -25, 30, 34, 8, -38, - -3, 18, 16, -31, 22, -4, -9, 1, - 20, 9, 38, -32, 0, -45, 0, -6, - -13, 11, -25, -32, -22, 31, -24, -11, - -11, -4, -4, 20, -34, 22, 20, 9, - -25, 27, -5, 28, -29, 29, 6, 21, - -6, -18, 54, 4, -46, 23, 21, -14, - -31, 36, -41, -24, 4, 22, 10, 11, - 7, 36, -32, -13, -52, -17, 24, 28, - -37, -36, -1, 24, 9, -38, 35, 48, - 18, 2, -1, 45, 10, 39, 24, -38, - 13, 8, -16, 8, 25, 11, 7, -29, - -11, 7, 20, -30, -38, -45, 14, -18, - -28, -9, 65, 61, 22, -53, -38, -16, - 36, 46, 20, -39, 32, -61, -6, -6, - -36, -33, -18, -28, 56, 101, 45, 11, - -28, -23, -29, -61, 20, -47, 2, 48, - 27, -17, 1, 40, 1, 3, -51, 15, - 35, 28, 22, 35, 53, -61, -29, 12, - -6, -21, 10, 3, -20, 2, -25, 1, - -6, 31, 11, -3, 1, -10, -52, 6, - 126, -105, 122, 127, -128, 127, 127, -128, - 127, 108, 12, 127, 48, -128, -36, -128, - 127, 127, -128, -128, 127, 89, -128, 127, - -128, -128, -128, 127, 127, -128, -128, -93, - -82, 20, 125, 65, -82, 127, 38, -74, - 81, 88, -88, 79, 51, -47, -111, -26, - 14, 83, -88, -112, 24, 35, -101, 98, - -99, -48, -45, 46, 83, -60, -79, 45, - -20, -41, 9, 4, 52, 54, 93, -10, - 4, 13, 3, 123, 6, 94, -111, -69, - -14, -31, 10, 12, 53, -79, -11, -21, - -2, -44, -72, 92, 65, -57, 56, -38, - 127, -56, -128, 127, 127, -128, 86, 117, - -75, -128, 127, -19, -99, -112, 127, -128, - 127, -48, 114, 118, -128, -128, 117, -17, - -6, 121, -128, 127, -128, 82, 54, -106, - 127, 127, -33, 100, -39, -23, 18, -78, - -34, -29, -1, -30, 127, -26, 127, -128, - 126, -128, 27, -23, -79, -120, -127, 127, - 72, 66, 29, 7, -66, -56, -117, -128 -}; - -static const opus_int8 layer0_bias[32] = { - 51, -16, 1, 13, -5, -6, -16, -7, - 11, -6, 106, 26, 28, -14, 21, -29, - 7, 18, -18, -17, 21, -17, -9, 20, - -25, -3, -34, 48, 11, -13, -31, -20 -}; - -static const opus_int8 layer1_weights[2304] = { - 22, -1, -7, 7, 29, -27, -31, -17, - -13, 33, 44, -8, 11, 33, 24, 78, - 15, 19, 30, -2, -24, 5, 49, 5, - 36, 29, -14, -11, -48, -33, 21, -42, - -38, -12, 55, -37, 54, -8, 1, 36, - 17, 0, 51, 31, 59, 7, -12, 53, - 4, 32, -14, 48, 5, -10, -16, -8, - 1, -16, -56, -24, -6, 18, -2, 23, - 6, 46, -6, -10, 20, 35, -44, -15, - -49, 36, 16, 5, -7, -79, -67, 12, - 70, -3, -79, -54, -85, -24, 47, -22, - 33, 21, 69, -1, 11, 22, 14, -16, - -16, -22, -28, -11, 11, -41, 31, -26, - -33, -19, -4, 27, 32, -50, 5, -10, - -38, -22, -8, 35, -31, 1, -41, -15, - -11, 44, 28, -17, -41, -23, 17, 2, - -23, -26, -13, -13, -17, 6, 14, -31, - -25, 9, -19, 39, -8, 4, 31, -1, - -45, -11, -28, -92, -46, -15, 21, 118, - -22, 45, -51, 11, -20, -20, -15, 13, - -21, -97, -29, -32, -23, -42, 94, 1, - 23, -8, 63, -3, -46, 19, -26, 32, - -40, -74, -26, 26, -4, -13, 30, -20, - -30, -25, -14, -31, -45, -43, 4, -60, - -48, -12, -34, 2, 2, 3, 13, 15, - 11, 16, 5, 46, -9, -55, -16, -57, - 29, 14, 38, -50, -2, -44, -11, -8, - 52, -27, -38, -7, 20, 47, 17, -59, - 0, 47, 46, -63, 35, -17, 19, 33, - 68, -19, 2, 15, -16, 28, -16, -103, - 26, -35, 47, -39, -60, 30, 31, -23, - -52, -13, 116, 47, -25, 30, 40, 30, - -22, 2, 12, -27, -18, 31, -10, 27, - -8, -66, 12, 14, 4, -26, -28, -13, - 3, 13, -26, -51, 37, 5, 2, -21, - 47, 3, 13, 25, -41, -27, -8, -4, - 5, -76, -33, 28, 10, 9, -46, -74, - 19, 28, 25, 31, 54, -55, 68, 38, - -24, -32, 2, 4, 68, 11, -1, 99, - 5, 16, -2, -74, 40, 26, -26, 33, - 31, -1, -68, 14, -6, 25, 9, 29, - 60, 61, 7, -7, 0, -24, 7, 77, - 4, -1, 16, -7, 13, -15, -19, 28, - -31, -24, -16, 37, 24, 13, 30, 10, - -30, 11, 11, -10, 22, 60, 28, 45, - -3, -40, -62, -5, -102, 9, -32, -27, - -54, 21, 15, -5, 37, -43, -11, 37, - -19, 47, -64, -128, -27, -114, 21, -66, - 59, 46, -3, -12, -87, -9, 4, 19, - -113, -36, 78, 57, -26, -38, -77, -10, - 6, 6, -75, 25, -97, -11, 33, -46, - 1, 13, -21, -33, -20, 16, -6, -3, - -11, -4, -27, 38, 8, -41, -2, -33, - 18, 19, -26, 1, -29, -22, -4, -14, - -55, -11, -80, -3, 11, 34, 90, 51, - 11, 17, 43, 36, 127, -32, 29, 103, - 9, 27, 13, 64, 56, 70, -14, 3, - -12, 10, 37, 3, 12, -22, -10, 46, - 28, 10, 20, 26, -24, 18, 9, 7, - 14, 34, -5, -7, 31, -14, -56, 11, - -18, -8, -17, -7, -10, -40, 10, -33, - -32, -43, 5, 9, 11, -4, 10, 50, - -12, -5, 46, 9, 7, 1, 11, 15, - 91, -17, 7, -50, 23, 6, -30, -99, - 0, -17, 14, 8, -10, -25, -30, -69, - -62, 31, 127, 114, -23, 101, -5, -54, - -6, -22, 7, -56, 39, 18, -29, 0, - 46, 8, -79, 4, -21, 18, -32, 62, - -12, -8, -12, -58, 31, -32, 17, 6, - -24, 25, 24, 9, -4, -19, 45, 6, - 17, -14, 5, -27, 16, -4, -41, 25, - -36, 5, 15, 12, 50, 27, 25, 23, - -44, -69, -9, -19, -48, -8, 4, 12, - -6, 13, -19, -30, -36, 26, 37, -1, - -3, -30, -42, -14, -10, -20, 26, -54, - -27, -44, 4, 73, -26, 90, 32, -69, - -29, -16, 3, 103, 15, -17, 37, 24, - -23, -31, 33, -37, -64, 25, 13, -81, - -28, -32, 27, 5, -35, -23, 15, -22, - 19, -7, 9, 30, 19, -23, 27, -13, - 43, 29, -29, -6, 9, -40, -33, -33, - -32, 9, 11, -48, -8, -23, -52, 46, - 17, -22, -42, 35, -15, -41, 16, 34, - 31, -42, -19, -11, 55, 7, -39, 89, - -11, -33, 20, -14, 22, 32, 3, -17, - -6, 14, 34, 1, 55, -21, -90, -8, - 18, 27, 13, -29, 21, 15, -33, -51, - -9, -11, 4, -16, -18, 23, -4, -4, - 48, 1, 7, 29, -14, -12, -16, 17, - 35, 8, 0, -7, -2, 9, 8, 17, - -6, 53, -32, -21, -50, 5, 99, -60, - -5, -53, 10, -31, 12, -5, 7, 80, - 36, 18, -31, 9, 98, 36, -63, -35, - 4, -13, -28, -24, 28, -13, 18, 16, - -1, -18, -34, 10, 20, 7, 4, 29, - 11, 25, -7, 36, 14, 45, 24, 1, - -16, 30, 6, 35, -6, -11, -24, 13, - -1, 27, 39, 20, 48, -11, -4, -13, - 28, 11, -31, -18, 31, -29, 22, -2, - -20, -16, 5, 30, -12, -28, -3, 93, - -16, 23, 18, -29, 6, -54, -37, 28, - -3, -3, -47, -3, -36, -55, -3, 41, - -10, 47, -2, 23, 42, -7, -71, -27, - 83, -64, 7, -24, 8, 26, -17, 15, - 12, 31, -30, -38, -13, -33, -56, 4, - -17, 20, 18, 1, -30, -5, -6, -31, - -14, -37, 0, 22, 10, -30, 37, -17, - 18, 6, 5, 23, -36, -32, 14, 18, - -13, -61, -52, -69, 44, -30, 16, 18, - -4, -25, 14, 81, 26, -8, -23, -59, - 52, -104, 17, 119, -32, 26, 17, 1, - 23, 45, 29, -64, -57, -14, 73, 21, - -13, -13, 9, -68, -7, -52, 3, 24, - -39, 44, -15, 27, 14, 19, -9, -28, - -11, 5, 3, -34, -2, 2, 22, -6, - -23, 4, 3, 13, -22, -13, -10, -18, - 29, 6, 44, -13, -24, -8, 2, 30, - 14, 43, 6, 17, -73, -6, -7, 20, - -80, -7, -7, -28, 15, -69, -38, -5, - -100, -35, 15, -79, 23, 29, -18, -27, - 21, -66, -37, 8, -22, -39, 48, 4, - -13, 1, -9, 11, -29, 22, 6, -49, - 32, -14, 47, -18, -4, 44, -52, -74, - 43, 30, 23, -14, 5, 0, -27, 4, - -7, 10, -4, 10, 1, -16, 11, -18, - -2, -5, 2, -11, 0, -20, -4, 38, - 74, 59, 39, 64, -10, 26, -3, -40, - -68, 3, -30, -51, 8, -19, -27, -46, - 51, 52, 54, 36, 90, 92, 14, 13, - -5, 0, 16, -62, 16, 11, -47, -37, - -6, -5, 21, 54, -57, 32, 42, -6, - 62, -9, 16, 21, 24, 9, -10, -4, - 33, 50, 13, -15, 1, -35, -48, 18, - -11, -17, -67, -13, 21, 38, -44, 36, - -16, 29, 17, 5, -10, 18, 17, -32, - 2, 8, 22, -56, -15, -32, 40, 43, - 19, 46, -7, -100, -96, 19, 53, 24, - 21, -26, -48, -101, -82, 61, 38, -85, - -28, -34, -1, 63, -5, -5, 39, 39, - -38, 32, -12, -28, 20, 40, -8, 2, - 31, 12, -35, -13, 20, -25, 30, 8, - 3, -13, -9, -20, 2, -13, 24, 37, - -10, 33, 6, 20, -16, -24, -6, -6, - -19, -5, 22, 21, 10, 11, -4, -39, - -1, 6, 49, 41, -15, -57, 21, -62, - 77, -69, -13, 0, -74, 1, -7, -38, - -8, 6, 63, 28, 4, 26, -52, 82, - 63, 13, 45, -33, 44, -52, -65, -21, - -46, -49, 64, -17, 32, 24, 68, -39, - -16, -5, -26, 28, 5, -61, -28, 2, - 24, 11, -12, -33, 9, -37, -3, -28, - 22, -37, -12, 19, 0, -18, -2, 14, - 1, 4, 8, -9, -2, 43, -17, -2, - -66, -31, 56, -40, -87, -36, -2, -4, - -42, -45, -1, 31, -43, -15, 27, 63, - -11, 32, -10, -33, 27, -19, 4, 15, - -26, -34, 29, -4, -39, -65, 14, -20, - -21, -17, -36, 13, 59, 47, -38, -33, - 13, -37, -8, -37, -7, -6, -76, -31, - -12, -46, 7, 24, -21, -30, -14, 9, - 15, -12, -13, 47, -27, -25, -1, -39, - 0, 20, -9, 6, 7, 4, 3, 7, - 39, 50, 22, -7, 14, -20, 1, 70, - -28, 29, -41, 10, -16, -5, -28, -2, - -37, 32, -18, 17, 62, -11, -20, -50, - 36, 21, -62, -12, -56, 52, 50, 17, - 3, 48, 44, -41, -25, 3, 16, -3, - 0, 33, -6, 15, 27, 34, -25, 22, - 9, 17, -11, 36, 16, -2, 12, 21, - -52, 45, -2, -10, 46, 21, -18, 67, - -28, -13, 30, 37, 42, 16, -9, 11, - 75, 7, -64, -40, -10, 29, 57, -23, - 5, 53, -77, 3, -17, -5, 47, -55, - -35, -36, -13, 52, -53, -71, 52, -111, - -23, -26, -28, 29, -43, 55, -19, 43, - -19, 54, -12, -33, -44, -39, -19, -10, - -31, -10, 21, 38, -57, -20, 2, -25, - 8, -6, 50, 12, 15, 25, -25, 15, - -30, -6, 9, 25, 37, 19, -4, 31, - -22, 2, 4, 2, 36, 7, 3, -34, - -80, 36, -10, -2, -5, 31, -36, 49, - -70, 20, -36, 21, 24, 25, -46, -51, - 36, -58, -48, -40, -10, 55, 71, 47, - 10, -1, 1, 2, -46, -68, 16, 13, - 0, -74, -29, 73, -52, -18, -11, 7, - -44, -82, -32, -70, -28, -1, -39, -68, - -6, -41, 12, -22, -16, 40, -11, -25, - 51, -9, 21, 4, 4, -34, 7, -78, - 16, 6, -38, -30, -2, -44, 32, 0, - 22, 64, 5, -72, -2, -14, -10, -16, - -8, -25, 12, 102, -58, 37, -10, -23, - 15, 49, 7, -7, 2, -20, -32, 45, - -6, 48, 28, 30, 33, -1, 22, -6, - 30, 65, -17, 29, 74, 37, -26, -10, - 15, -24, 19, -66, 22, -10, -31, -1, - -18, -9, 11, 37, -4, 45, 5, 41, - 17, 1, 1, 24, -58, 41, 5, -51, - 14, 8, 43, 16, -10, -1, 45, 32, - -64, 3, -33, -25, -3, -27, -68, 12, - 23, -11, -13, -37, -40, 4, -21, -12, - 32, -23, -19, 76, 41, -23, -24, -44, - -65, -1, -15, 1, 71, 63, 5, 20, - -3, 21, -23, 31, -32, 18, -2, 27, - 31, 46, -5, -39, -5, -35, 18, -18, - -40, -10, 3, 12, 2, -2, -22, 40, - 5, -6, 60, 36, 3, 29, -27, 10, - 25, -54, 5, 26, 39, 35, -24, -37, - 30, -91, 28, -4, -21, -27, -39, -6, - 5, 12, -128, 38, -16, 29, -95, -29, - 82, -2, 35, 2, 12, 8, -22, 10, - 80, -47, 2, -25, -73, -79, 16, -30, - -32, -66, 48, 21, -45, -11, -47, 14, - -27, -17, -7, 15, -44, -14, -44, -26, - -32, 26, -23, 17, -7, -28, 26, -6, - 28, 6, -26, 2, 13, -14, -23, -14, - 19, 46, 16, 2, -33, -21, 28, -17, - -42, 44, -37, 1, -39, 28, 84, -46, - 15, 10, 13, -44, 72, -26, 26, 32, - -28, -12, -83, 2, 10, -30, -44, -10, - -28, 53, 45, 65, 0, -25, 57, 36, - -33, 6, 29, 44, -53, 11, 19, -2, - -27, 35, 32, 49, 4, 23, 38, 36, - 24, 10, 51, -39, 4, -7, 26, 37, - -35, 11, -47, -18, 28, 16, -35, 42, - 17, -21, -41, 28, 14, -12, 11, -45, - 7, -43, -15, 18, -5, 38, -40, -50, - -30, -21, 9, -98, 13, 12, 23, 75, - -56, -7, -3, -4, -1, -34, 12, -49, - 11, 26, -18, -28, -17, 33, 13, -14, - 40, 24, -72, -37, 10, 17, -6, 22, - 16, 16, -6, -12, -30, -14, 10, 40, - -23, 12, 15, -3, -15, 13, -56, -4, - -30, 1, -3, -17, 27, 50, -5, 64, - -36, -19, 7, 29, 22, 25, 9, -16, - -58, -69, -40, -61, -71, -14, 42, 93, - 26, 11, -6, -58, -11, 70, -52, 19, - 9, -30, -33, 11, -37, -47, -21, -22, - -40, 10, 47, 4, -23, 17, 48, 41, - -48, 14, 10, 15, 34, -23, -2, -47, - 23, -32, -13, -10, -26, -26, -4, 16, - 38, -14, 0, -12, -7, -7, 20, 44, - -1, -32, -27, -16, 4, -6, -18, 14, - 5, 4, -29, 28, 7, -7, 15, -11, - -20, -45, -36, 16, 84, 34, -59, -30, - 22, 126, 8, 68, 79, -17, 21, -68, - 37, 5, 15, 63, 49, 127, -90, 85, - 43, 7, 16, 9, 6, -45, -57, -43, - 57, 11, -23, -11, -29, 60, -26, 0, - 7, 42, -24, 10, 23, -25, 8, -7, - -40, 19, -17, 35, 4, 27, -39, -91, - 27, -36, 34, 2, 16, -24, 25, 7, - -21, 5, 17, 10, -22, -30, 9, -17, - -61, -26, 33, 21, 58, -51, -14, 69, - -38, 20, 7, 80, -4, -65, -6, -27, - 53, -12, 47, -1, -15, 1, 60, 102, - -79, -4, 12, 9, 22, 37, -8, -4, - 37, 2, -3, -15, -16, -11, -5, 19, - -6, -43, 20, -25, -18, 10, -27, 0, - -28, -27, -11, 10, -18, -2, -4, -16, - 26, 14, -6, 7, -6, 1, 53, -2, - -29, 23, 9, -30, -6, -4, -6, 56, - 70, 0, -33, -20, -17, -9, -24, 46, - -5, -105, 47, -46, -51, 20, 20, -53, - -81, -1, -7, 75, -5, -21, -65, 12, - -52, 22, -50, -12, 49, 54, 76, -81, - 10, 45, -41, -59, 18, -19, 25, 14, - -31, -53, -5, 12, 31, 84, -23, 2, - 7, 2, 10, -32, 39, -2, -12, 1, - -9, 0, -10, -11, 9, 15, -8, -2, - 2, -1, 10, 14, -5, -40, 19, -7, - -7, 26, -4, 2, 1, -27, 35, 32, - 21, -31, 26, 43, -9, 4, -32, 40, - -62, -52, 36, 22, 38, 22, 36, -96, - 6, -10, -23, -49, 15, -33, -18, -3, - 0, 41, 21, -19, 21, 23, -39, -23, - -6, 6, 47, 56, 4, 74, 0, -98, - 29, -47, -14, -36, 21, -22, 22, 16, - 13, 12, 16, -5, 13, 17, -13, -15, - 1, -34, -26, 26, 12, 32, 27, 13, - -67, 27, 2, 8, 10, 18, 16, 20, - -17, -17, 57, -64, 5, 14, 19, 31, - -18, -44, -46, -16, 4, -25, 17, -126, - -24, 39, 4, 8, 55, -25, -34, 39, - -16, 3, 9, 71, 72, -31, -55, 6, - 10, -25, 32, -85, -21, 18, -8, 15, - 12, -27, -7, 1, -21, -2, -5, 48, - -16, 18, 1, -22, -26, 16, 14, -31, - 27, -6, -15, -21, 4, -14, 18, -36 -}; - -static const opus_int8 layer1_recur_weights[1728] = { - 20, 67, -99, 12, 41, -25, 49, -44, - 35, 81, 110, 47, 34, -66, -14, 14, - -60, 34, 29, -73, 10, 41, 35, 89, - 7, -35, 22, 7, 27, -20, -6, 56, - 26, 66, 6, 33, -55, 53, 1, -21, - 14, 17, 68, 55, 59, 0, 18, -9, - 5, -41, 6, -5, -114, -12, 29, 42, - -23, 10, 81, -27, 20, -53, -30, -62, - 40, 95, 25, -4, 3, 18, -8, -15, - -29, -82, 2, -57, -3, -61, -29, -29, - 49, 2, -55, 5, -69, -99, -49, -51, - 6, -25, 12, 89, 44, -33, 5, 41, - 1, 23, -37, -37, -28, -48, 3, 4, - -41, -30, -57, -35, -39, -1, -13, -56, - -5, 50, 49, 41, -4, -4, 33, -22, - -1, 33, 34, 18, 40, -42, 12, 1, - -6, -2, 18, 17, 39, 44, 11, 65, - -60, -45, 10, 91, 21, 9, -62, -11, - 8, 69, 37, 24, -30, 21, 26, -27, - 1, -28, 24, 66, -8, 6, -71, 34, - 24, 44, 58, -78, -19, 57, 17, -60, - 1, 12, -3, -1, -40, 22, 11, -5, - 25, 12, 1, 72, 79, 7, -50, 23, - 18, 13, 21, -11, -20, 5, 77, -94, - 24, 15, 57, -51, 3, 36, 53, -1, - 4, 14, 30, -31, 22, 40, 32, -11, - -34, -36, -59, 58, 25, 21, -54, -23, - 40, 46, 18, 0, 12, 54, -96, -99, - -59, 5, 119, -38, 50, 55, 12, -16, - 67, 0, 34, 35, 39, 35, -1, 69, - 24, 27, -30, -35, -4, -70, 2, -44, - -7, -6, 19, -9, 60, 44, -21, -10, - 37, 43, -16, -3, 30, -15, -65, 31, - -55, 18, -98, 76, 64, 25, 24, -18, - -7, -68, -10, 38, 27, -60, 36, 33, - 16, 30, 34, -39, -37, 31, 12, 53, - -54, 14, -26, -49, -128, -13, -5, -22, - -11, -85, 55, -8, -51, -11, -33, -10, - -31, -76, -41, 23, 44, -40, -54, -127, - -101, 19, -23, -15, 15, 27, 58, -60, - 8, 14, -33, 1, 48, -9, -11, -123, - 3, 53, 23, 4, -28, 22, 2, -29, - -67, 36, 12, 7, 55, -21, 88, 20, - -1, -21, -17, 3, 41, 32, -10, -14, - -5, -57, 67, 57, 21, 23, -2, -27, - -73, -24, 120, 21, 18, -35, 42, -7, - 3, -45, -25, 76, -34, 50, 11, -54, - -91, 3, -113, -20, -5, 47, 15, -47, - 17, 27, -3, -26, -7, 10, 7, 74, - -40, 64, -7, -5, -24, -49, -24, -3, - -10, 27, -17, -8, -3, 14, -27, 33, - 13, 39, 28, -7, -38, 29, 16, 44, - 19, 55, -3, 9, -13, -57, 43, 43, - 31, 0, -93, -17, 19, -56, 4, -12, - -25, 37, -85, -13, -118, 33, -17, 56, - 71, -80, -4, 6, -11, -18, 47, -52, - 25, 9, 48, -107, 1, 21, 20, -3, - 10, -16, -4, 24, 17, 31, -61, -18, - -50, 24, -10, 12, 71, 26, 11, -3, - 4, 1, 0, -7, -40, 18, 38, -34, - 38, 17, 8, -34, 2, 21, 123, -32, - -26, 43, 14, -34, -1, -9, 37, -16, - 6, -17, -62, 68, 22, 17, 11, -75, - 33, -80, 62, -9, -75, 76, 36, -41, - -8, -40, -11, -71, 40, -39, 62, -49, - -81, 16, -9, -52, 52, 61, 17, -103, - -27, -10, -8, -54, -57, 21, 23, -16, - -52, 36, 18, 10, -5, 8, 15, -29, - 5, -19, -37, 8, -53, 6, 19, -37, - 38, -17, 48, 10, 0, 81, 46, 70, - -29, 101, 11, 44, -44, -3, 24, 11, - 3, 14, -9, 11, 14, -45, 13, 46, - -3, -57, 68, 44, 63, 98, 25, -28, - -23, 15, 32, -10, 53, -6, -2, -9, - -6, 16, -107, -11, -11, -28, 59, 57, - -22, 38, 42, 83, 27, 5, 29, -30, - 12, -21, -13, 31, 38, -21, 58, -10, - -10, -15, -2, -5, 11, 12, -73, -28, - -38, 22, 2, -25, 73, -52, -12, -55, - 32, -63, 21, 51, 33, 52, -26, 55, - -26, -26, 57, -32, -4, -52, -61, 21, - -33, -91, -51, 69, -90, -53, -38, -44, - 12, -76, -20, 77, -45, -7, 86, 43, - -109, -33, -105, -40, -121, -10, 0, -72, - 45, -51, -75, -49, -38, -1, -62, 18, - -1, 30, -44, -14, -10, -67, 40, -10, - -34, 46, -64, -32, 29, -13, 33, 3, - -32, -5, 28, -27, -25, 93, 24, 68, - -40, 57, 23, -3, -21, -58, 17, -39, - -17, -22, -89, 11, 18, -46, 27, 24, - 46, 127, 61, 87, 31, 127, -36, 47, - -23, 47, 127, -24, 110, 122, 30, 100, - 0, 96, -12, 6, 50, 44, -13, 73, - 4, 55, -11, -15, 49, 42, -6, 20, - -35, 58, 18, 38, 42, 72, 19, -21, - 11, 9, -37, 7, 29, 31, 16, -17, - 13, -50, 19, 5, -23, 51, -16, -5, - 4, -24, 76, 10, -53, -28, -7, -65, - 74, 40, -16, -29, 32, -16, -49, -35, - -3, 59, -96, -50, -43, -43, -61, -15, - -8, -36, -34, -33, -14, 11, -3, -39, - 4, -114, -123, -11, -49, -21, 14, -56, - 1, 43, -63, 26, 40, 18, -10, -26, - -14, -15, -35, -35, -11, 32, -44, -67, - 2, 22, 7, 3, -9, -30, -51, -28, - 28, 6, -22, 16, 34, -25, -52, -54, - -8, -6, 5, 8, 20, -16, -17, -44, - 27, 3, 31, -5, -48, -1, -3, 116, - 11, 71, -31, -47, 109, 50, -22, -12, - -57, 32, 66, 8, -25, -93, -54, -10, - 19, -76, -34, 97, 48, -36, -18, -30, - -39, -26, -12, 28, 14, 12, -12, -31, - 38, 2, 10, 4, -40, 20, 16, -61, - 2, 64, 39, 5, 15, 33, 40, -61, - -49, 93, -10, 33, 28, -11, -27, -18, - 39, -62, -6, -6, 62, 11, -8, 38, - -67, 12, 27, 39, -27, 123, -18, -6, - -65, 83, -64, 20, 19, -11, 33, 24, - 17, 56, 78, 7, -15, 54, -101, -9, - 115, -96, 50, 51, 35, 34, 27, 37, - -40, -11, 8, -36, 42, -45, 2, -23, - 0, 67, -8, -9, -13, 50, -14, -27, - 4, 0, -8, -14, 30, -9, 29, 15, - 9, -38, 37, -8, 50, -46, 54, 41, - -11, -8, -11, -26, 39, 45, 14, -26, - -17, -27, 69, 38, 39, 98, 66, 0, - 42, 123, -101, -19, -83, 117, -32, 56, - 10, 12, -88, 79, -53, 56, 63, 95, - -62, 9, 36, -13, -79, -16, 37, -46, - 35, -34, 14, 17, -54, 5, 21, -7, - 7, 63, 56, 15, 27, -76, -25, 4, - -26, -63, 28, -67, -52, 43, -47, -70, - 40, -12, 40, -66, -37, 0, 35, 37, - -53, 4, -17, -51, 11, 21, 14, -34, - -4, 24, -42, 29, 22, 7, 28, 12, - 37, 39, -39, -19, 65, -60, -50, -2, - 1, 82, 39, 19, -23, -43, -22, -67, - -35, -34, 32, 102, 81, 127, 36, 67, - -45, 1, -67, -52, -4, 35, 20, 28, - 71, 86, -35, -9, -83, -34, 12, 9, - -23, 2, 14, 28, -23, 7, -25, 45, - 7, 17, -37, 0, -19, 31, 26, 40, - -27, -16, 17, 5, -21, 23, 24, 96, - -55, 52, -19, -14, -6, 1, 50, -34, - 86, -53, 38, 2, -52, -36, -13, 60, - -85, -120, 32, 7, -12, 22, 70, -7, - -94, 38, -76, -31, -20, 15, -28, 7, - 6, 40, 53, 88, 3, 38, 18, -8, - -22, -23, 51, 37, -9, 13, -32, 25, - -21, 27, 31, 20, 18, -9, -13, 1, - 21, -24, -13, 39, 15, -11, -29, -36, - 18, 15, 8, 27, 21, -94, -1, -22, - 49, 66, -1, 6, -3, -40, -18, 6, - 28, 12, 33, -59, 62, 60, -48, 90, - -1, 108, 9, 18, -2, 27, 77, -65, - 82, -48, -38, -19, -11, 127, 50, 66, - 18, -13, -22, 60, -38, 40, -14, -26, - -13, 38, 67, 57, 30, 33, 26, 36, - 38, -17, 27, -28, 20, 12, -64, 18, - 5, -33, -27, 13, -26, 32, 35, -5, - -48, -14, 92, 43, -47, -14, 40, 11, - 51, 66, 22, -63, -16, -61, 4, -28, - 27, 20, -33, -30, -21, -29, -53, 31, - -40, 24, 43, -4, -19, 21, 67, 20, - 100, -16, -93, 78, -6, -18, -52, -37, - -9, 66, -31, -8, 26, 18, 4, 24, - -22, 17, -2, -13, 27, 0, 8, -18, - -25, 5, -21, -24, -7, 18, -93, 21, - 7, 2, -75, 69, 50, -5, -15, -17, - 60, -42, 55, 1, -4, 3, 10, 46, - 16, -13, 45, -7, -10, -44, -108, 49, - 2, -15, -64, -12, -72, 32, -38, -45, - 10, -54, 13, -13, -27, -36, -64, 58, - -62, -101, 88, -86, -71, -39, -9, -128, - 32, 15, -4, 54, -16, -39, -26, -36, - 46, 48, -64, -10, 19, 30, -13, 34, - -8, 50, 60, -22, -6, -11, -30, 5, - 50, 32, 56, 0, 25, 6, 68, 11, - -29, 45, -9, -12, 4, 1, 18, -49, - 0, -38, -19, 90, 29, 35, 51, 8, - -48, 96, -1, -12, -9, -32, -63, -65, - -7, 38, 89, 28, -85, -28, -23, -25, - -128, 56, 79, -36, 99, -6, -37, 7, - -13, -69, -46, -29, 25, 64, -21, 17, - 1, 42, -66, 1, 80, 26, -32, 21, - 15, 15, 6, 6, -10, 15, 127, 5, - 38, 27, 87, -57, -25, 11, 72, -21, - -5, 11, -13, -66, 78, 36, -3, 41, - -21, 8, -33, 23, 73, 28, 57, -25, - -5, 4, -22, -47, 15, 4, -57, -72, - 33, 1, 18, 2, 53, -71, -99, -21, - -3, -111, 108, 71, -14, 82, 25, 61, - -48, 5, 9, -51, -20, -25, -3, 14, - -33, 14, -3, -34, 22, 12, -19, -38, - -16, 2, 21, 16, 26, -31, 75, 44, - -31, 16, 26, 66, 17, -9, -22, -22, - 22, -44, 22, 27, 2, 58, -14, 10, - -73, -42, 55, -25, -61, 72, -1, 30, - -58, -25, 63, 26, -48, -40, 26, -30, - 60, 8, -17, -1, -18, -20, 43, -20, - -4, -28, 127, -106, 29, 70, 64, -27, - 39, -33, -5, -88, -40, -52, 26, 44, - -17, 23, 2, -49, 22, -9, -8, 86, - 49, -43, -60, 1, 10, 45, 36, -53, - -4, 33, 38, 48, -72, 1, 19, 21, - -65, 4, -5, -62, 27, -25, 17, -6, - 6, -45, -39, -46, 4, 26, 127, -9, - 18, -33, -18, -3, 33, 2, -5, 15, - -26, -22, -117, -63, -17, -59, 61, -74, - 7, -47, -58, -128, -67, 15, -16, -128, - 12, 2, 20, 9, -48, -40, 43, 3, - -40, -16, -38, -6, -22, -28, -16, -59, - -22, 6, -5, 11, -12, -66, -40, 27, - -62, -44, -19, 38, -3, 39, -8, 40, - -24, 13, 21, 50, -60, -22, 53, -29, - -6, 1, 22, -59, 0, 17, -39, 115 -}; +/* RMS error was 0.138320, seed was 1361535663 */ -static const opus_int8 layer1_bias[72] = { - -42, 20, 16, 0, 105, 60, 1, -97, - 24, 60, 18, 13, 62, 25, 127, 34, - 79, 55, 118, 127, 95, 31, -4, 87, - 21, 12, 2, -14, 18, 23, 8, 17, - -1, -8, 5, 4, 24, 37, 21, 13, - 36, 13, 17, 18, 37, 30, 33, 1, - 8, -16, -11, -5, -31, -3, -5, 0, - 6, 3, 58, -7, -1, -16, 5, -13, - 16, 10, -2, -14, 11, -4, 3, -11 -}; +static const float weights[422] = { -static const opus_int8 layer2_weights[48] = { - -113, -88, 31, -128, -126, -61, 85, -35, - 118, -128, -61, 127, -128, -17, -128, 127, - 104, -9, -128, 33, 45, 127, 5, 83, - 84, -128, -85, -128, -45, 48, -53, -128, - 46, 127, -17, 125, 117, -41, -117, -91, - -127, -68, -1, -89, -80, 32, 106, 7 -}; +/* hidden layer */ +-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f, +-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f, +-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f, +0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f, +0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f, +24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f, +-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f, +-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f, +-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f, +1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f, +15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f, +0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f, +-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f, +0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f, +0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f, +-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f, +-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f, +-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f, +0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f, +-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f, +2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f, +0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f, +-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f, +0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f, +0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f, +-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f, +5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f, +-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f, +-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f, +-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f, +1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f, +-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f, +-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f, +0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f, +0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f, +-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f, +10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f, +-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f, +-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f, +-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f, +0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f, +-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f, +0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f, +0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f, +-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f, +0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f, +-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f, +-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f, +-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f, +-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f, +-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f, +5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f, +1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f, +0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f, +-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f, +0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f, +-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f, +-975268.f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f, +0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f, +-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f, +-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f, +0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f, +-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f, +0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f, +-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f, +-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f, +0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f, +-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f, +0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f, +-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f, +0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f, +-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f, +4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f, +0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f, +-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f, +0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f, +0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f, +3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f, -static const opus_int8 layer2_bias[2] = { - 14, 117 -}; +/* output layer */ +-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f, +0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f, +0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f, +0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f, +4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f, +-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f, +3.87308f, 3.52558f}; -const DenseLayer layer0 = { - layer0_bias, - layer0_weights, - 25, 32, 0 -}; +static const int topo[3] = {25, 15, 2}; -const GRULayer layer1 = { - layer1_bias, - layer1_weights, - layer1_recur_weights, - 32, 24 +const MLP net = { + 3, + topo, + weights }; - -const DenseLayer layer2 = { - layer2_bias, - layer2_weights, - 24, 2, 1 -}; - diff --git a/thirdparty/opus/opus.c b/thirdparty/opus/opus.c index 538b5ea74e..f76f125cfa 100644 --- a/thirdparty/opus/opus.c +++ b/thirdparty/opus/opus.c @@ -107,7 +107,7 @@ OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem) /* 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; + a += a*2.4e-7; if (x[i*C]>0) a = -a; /* Apply soft clipping */ @@ -252,7 +252,7 @@ int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, /* Number of frames encoded in bits 0 to 5 */ ch = *data++; count = ch&0x3F; - if (count <= 0 || framesize*(opus_int32)count > 5760) + if (count <= 0 || framesize*count > 5760) return OPUS_INVALID_PACKET; len--; /* Padding flag is bit 6 */ diff --git a/thirdparty/opus/opus/opus.h b/thirdparty/opus/opus/opus.h index d282f21d25..5be73ddf4e 100644 --- a/thirdparty/opus/opus/opus.h +++ b/thirdparty/opus/opus/opus.h @@ -531,7 +531,7 @@ OPUS_EXPORT int opus_packet_parse( const unsigned char *frames[48], opus_int16 size[48], int *payload_offset -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5); +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); /** Gets the bandwidth of an Opus packet. * @param [in] data <tt>char*</tt>: Opus packet diff --git a/thirdparty/opus/opus/opus_defines.h b/thirdparty/opus/opus/opus_defines.h index d141418b21..315412dd1d 100644 --- a/thirdparty/opus/opus/opus_defines.h +++ b/thirdparty/opus/opus/opus_defines.h @@ -165,13 +165,8 @@ extern "C" { #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 +/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ /* 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)) @@ -213,9 +208,6 @@ extern "C" { #define OPUS_FRAMESIZE_20_MS 5004 /**< Use 20 ms frames */ #define OPUS_FRAMESIZE_40_MS 5005 /**< Use 40 ms frames */ #define OPUS_FRAMESIZE_60_MS 5006 /**< Use 60 ms frames */ -#define OPUS_FRAMESIZE_80_MS 5007 /**< Use 80 ms frames */ -#define OPUS_FRAMESIZE_100_MS 5008 /**< Use 100 ms frames */ -#define OPUS_FRAMESIZE_120_MS 5009 /**< Use 120 ms frames */ /**@}*/ @@ -574,9 +566,7 @@ extern "C" { * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd> * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd> * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd> - * <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd> - * <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd> - * <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd> + * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd> * </dl> * @hideinitializer */ #define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x) @@ -591,9 +581,7 @@ extern "C" { * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd> * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd> * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd> - * <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd> - * <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd> - * <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd> + * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd> * </dl> * @hideinitializer */ #define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x) @@ -693,40 +681,6 @@ extern "C" { */ #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 <tt>opus_int32</tt>: Allowed values: - * <dl> - * <dt>0</dt><dd>Enable phase inversion (default).</dd> - * <dt>1</dt><dd>Disable phase inversion.</dd> - * </dl> - * @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 <tt>opus_int32 *</tt>: Returns one of the following values: - * <dl> - * <dt>0</dt><dd>Stereo phase inversion enabled (default).</dd> - * <dt>1</dt><dd>Stereo phase inversion disabled.</dd> - * </dl> - * @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 <tt>opus_int32 *</tt>: Returns one of the following values: - * <dl> - * <dt>0</dt><dd>The encoder is not in DTX.</dd> - * <dt>1</dt><dd>The encoder is in DTX.</dd> - * </dl> - * @hideinitializer */ -#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) - /**@}*/ /** @defgroup opus_decoderctls Decoder related CTLs diff --git a/thirdparty/opus/opus/opus_multistream.h b/thirdparty/opus/opus/opus_multistream.h index babcee6905..3622e009fb 100644 --- a/thirdparty/opus/opus/opus_multistream.h +++ b/thirdparty/opus/opus/opus_multistream.h @@ -273,7 +273,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_enc unsigned char *mapping, int application, int *error -) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); +) OPUS_ARG_NONNULL(5); /** Initialize a previously allocated multistream encoder state. * The memory pointed to by \a st must be at least the size returned by @@ -342,7 +342,7 @@ OPUS_EXPORT int opus_multistream_surround_encoder_init( int *coupled_streams, unsigned char *mapping, int application -) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7); +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); /** Encodes a multistream Opus frame. * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state. diff --git a/thirdparty/opus/opus/opus_projection.h b/thirdparty/opus/opus/opus_projection.h deleted file mode 100644 index 9dabf4e85c..0000000000 --- a/thirdparty/opus/opus/opus_projection.h +++ /dev/null @@ -1,568 +0,0 @@ -/* 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 <tt>opus_int32 *</tt>: 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 <tt>opus_int32 *</tt>: 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 <tt>unsigned char *</tt>: Returns the demixing matrix to the - * supplied pointer location. - * @param y <tt>opus_int32</tt>: 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 <tt>int</tt>: The total number of input channels to encode. - * This must be no more than 255. - * @param mapping_family <tt>int</tt>: 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 <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels <tt>int</tt>: Number of channels in the input signal. - * This must be at most 255. - * It may be greater than the number of - * coded channels (<code>streams + - * coupled_streams</code>). - * @param mapping_family <tt>int</tt>: The mapping family to use for selecting - * the appropriate projection. - * @param[out] streams <tt>int *</tt>: The total number of streams that will - * be encoded from the input. - * @param[out] coupled_streams <tt>int *</tt>: Number of coupled (2 channel) - * streams that will be encoded from the input. - * @param application <tt>int</tt>: The target encoder application. - * This must be one of the following: - * <dl> - * <dt>#OPUS_APPLICATION_VOIP</dt> - * <dd>Process signal for improved speech intelligibility.</dd> - * <dt>#OPUS_APPLICATION_AUDIO</dt> - * <dd>Favor faithfulness to the original input.</dd> - * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt> - * <dd>Configure the minimum possible coding delay by disabling certain modes - * of operation.</dd> - * </dl> - * @param[out] error <tt>int *</tt>: 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 <tt>OpusProjectionEncoder*</tt>: Projection encoder state to initialize. - * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels <tt>int</tt>: Number of channels in the input signal. - * This must be at most 255. - * It may be greater than the number of - * coded channels (<code>streams + - * coupled_streams</code>). - * @param streams <tt>int</tt>: The total number of streams to encode from the - * input. - * This must be no more than the number of channels. - * @param coupled_streams <tt>int</tt>: 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 (<code>streams + - * coupled_streams</code>) must be no - * more than the number of input channels. - * @param application <tt>int</tt>: The target encoder application. - * This must be one of the following: - * <dl> - * <dt>#OPUS_APPLICATION_VOIP</dt> - * <dd>Process signal for improved speech intelligibility.</dd> - * <dt>#OPUS_APPLICATION_AUDIO</dt> - * <dd>Favor faithfulness to the original input.</dd> - * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt> - * <dd>Configure the minimum possible coding delay by disabling certain modes - * of operation.</dd> - * </dl> - * @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 <tt>OpusProjectionEncoder*</tt>: Projection encoder state. - * @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved - * samples. - * This must contain - * <code>frame_size*channels</code> - * samples. - * @param frame_size <tt>int</tt>: 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 <tt>unsigned char*</tt>: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes <tt>opus_int32</tt>: 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 <tt>OpusProjectionEncoder*</tt>: Projection encoder state. - * @param[in] pcm <tt>const float*</tt>: 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 - * <code>frame_size*channels</code> - * samples. - * @param frame_size <tt>int</tt>: 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 <tt>unsigned char*</tt>: Output payload. - * This must contain storage for at - * least \a max_data_bytes. - * @param [in] max_data_bytes <tt>opus_int32</tt>: 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 <code>OpusProjectionEncoder</code> allocated by - * opus_projection_ambisonics_encoder_create(). - * @param st <tt>OpusProjectionEncoder*</tt>: 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 <tt>OpusProjectionEncoder*</tt>: 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 <code>OpusProjectionDecoder</code> structure. - * @param channels <tt>int</tt>: The total number of output channels. - * This must be no more than 255. - * @param streams <tt>int</tt>: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams <tt>int</tt>: 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 (<code>streams + - * coupled_streams</code>) 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 <tt>opus_int32</tt>: Sampling rate to decode at (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels <tt>int</tt>: Number of channels to output. - * This must be at most 255. - * It may be different from the number of coded - * channels (<code>streams + - * coupled_streams</code>). - * @param streams <tt>int</tt>: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams <tt>int</tt>: 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 (<code>streams + - * coupled_streams</code>) must be no - * more than 255. - * @param[in] demixing_matrix <tt>const unsigned char[demixing_matrix_size]</tt>: 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 <tt>opus_int32</tt>: The size in bytes of the - * demixing matrix, as - * described in @ref - * opus_projection_ctls. - * @param[out] error <tt>int *</tt>: 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 <tt>OpusProjectionDecoder*</tt>: Projection encoder state to initialize. - * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz). - * This must be one of 8000, 12000, 16000, - * 24000, or 48000. - * @param channels <tt>int</tt>: Number of channels to output. - * This must be at most 255. - * It may be different from the number of coded - * channels (<code>streams + - * coupled_streams</code>). - * @param streams <tt>int</tt>: The total number of streams coded in the - * input. - * This must be no more than 255. - * @param coupled_streams <tt>int</tt>: 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 (<code>streams + - * coupled_streams</code>) must be no - * more than 255. - * @param[in] demixing_matrix <tt>const unsigned char[demixing_matrix_size]</tt>: 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 <tt>opus_int32</tt>: 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 <tt>OpusProjectionDecoder*</tt>: Projection decoder state. - * @param[in] data <tt>const unsigned char*</tt>: Input payload. - * Use a <code>NULL</code> - * pointer to indicate packet - * loss. - * @param len <tt>opus_int32</tt>: Number of bytes in payload. - * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved - * samples. - * This must contain room for - * <code>frame_size*channels</code> - * samples. - * @param frame_size <tt>int</tt>: 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 - * <b>must</b> be a multiple of 2.5 ms. - * @param decode_fec <tt>int</tt>: 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 <tt>OpusProjectionDecoder*</tt>: Projection decoder state. - * @param[in] data <tt>const unsigned char*</tt>: Input payload. - * Use a <code>NULL</code> - * pointer to indicate packet - * loss. - * @param len <tt>opus_int32</tt>: Number of bytes in payload. - * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved - * samples. - * This must contain room for - * <code>frame_size*channels</code> - * samples. - * @param frame_size <tt>int</tt>: 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 - * <b>must</b> be a multiple of 2.5 ms. - * @param decode_fec <tt>int</tt>: 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 <tt>OpusProjectionDecoder*</tt>: 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 <code>OpusProjectionDecoder</code> allocated by - * opus_projection_decoder_create(). - * @param st <tt>OpusProjectionDecoder</tt>: 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/thirdparty/opus/opus/opus_types.h b/thirdparty/opus/opus/opus_types.h index 7cf675580f..b28e03aea2 100644 --- a/thirdparty/opus/opus/opus_types.h +++ b/thirdparty/opus/opus/opus_types.h @@ -33,29 +33,14 @@ #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)) +#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) #include <stdint.h> -# 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__) @@ -163,4 +148,12 @@ #endif +#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 + #endif /* OPUS_TYPES_H */ diff --git a/thirdparty/opus/opus/opusfile.h b/thirdparty/opus/opus/opusfile.h index e3a3dc8389..4bf2fba926 100644 --- a/thirdparty/opus/opus/opusfile.h +++ b/thirdparty/opus/opus/opusfile.h @@ -239,8 +239,7 @@ struct OpusHead{ -32768...32767. The <tt>libopusfile</tt> API will automatically apply this gain to the decoded output before returning it, scaling it by - <code>pow(10,output_gain/(20.0*256))</code>. - You can adjust this behavior with op_set_gain_offset().*/ + <code>pow(10,output_gain/(20.0*256))</code>.*/ int output_gain; /**The channel mapping family, in the range 0...255. Channel mapping family 0 covers mono or stereo in a single stream. @@ -1155,18 +1154,16 @@ 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 <code>FILE *</code>). - This value will be passed verbatim as the first - argument to all of the callbacks. + \param _source The stream to read from (e.g., a <code>FILE *</code>). \param _cb The callbacks with which to access the stream. <code><a href="#op_read_func">read()</a></code> must be implemented. <code><a href="#op_seek_func">seek()</a></code> and <code><a href="#op_tell_func">tell()</a></code> may be <code>NULL</code>, or may always return -1 to - indicate a stream is unseekable, but if + indicate a source is unseekable, but if <code><a href="#op_seek_func">seek()</a></code> is - implemented and succeeds on a particular stream, then + implemented and succeeds on a particular source, then <code><a href="#op_tell_func">tell()</a></code> must also. <code><a href="#op_close_func">close()</a></code> may @@ -1229,11 +1226,11 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url, basic validity checks.</dd> </dl> \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error. - <tt>libopusfile</tt> does <em>not</em> take ownership of the stream + <tt>libopusfile</tt> does <em>not</em> take ownership of the source if the call fails. - The calling application is responsible for closing the stream if + The calling application is responsible for closing the source if this call returns an error.*/ -OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_stream, +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_source, const OpusFileCallbacks *_cb,const unsigned char *_initial_data, size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); @@ -1335,20 +1332,18 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url, 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 + sources, 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 <code>FILE *</code>). - This value will be passed verbatim as the first - argument to all of the callbacks. + \param _source The stream to read from (e.g., a <code>FILE *</code>). \param _cb The callbacks with which to access the stream. <code><a href="#op_read_func">read()</a></code> must be implemented. <code><a href="#op_seek_func">seek()</a></code> and <code><a href="#op_tell_func">tell()</a></code> may be <code>NULL</code>, or may always return -1 to - indicate a stream is unseekable, but if + indicate a source is unseekable, but if <code><a href="#op_seek_func">seek()</a></code> is - implemented and succeeds on a particular stream, then + implemented and succeeds on a particular source, then <code><a href="#op_tell_func">tell()</a></code> must also. <code><a href="#op_close_func">close()</a></code> may @@ -1378,11 +1373,11 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url, See op_open_callbacks() for a full list of failure codes. \return A partially opened \c OggOpusFile, or <code>NULL</code> on error. - <tt>libopusfile</tt> does <em>not</em> take ownership of the stream + <tt>libopusfile</tt> does <em>not</em> take ownership of the source if the call fails. - The calling application is responsible for closing the stream if + The calling application is responsible for closing the source if this call returns an error.*/ -OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_stream, +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_source, const OpusFileCallbacks *_cb,const unsigned char *_initial_data, size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); @@ -1439,7 +1434,7 @@ void op_free(OggOpusFile *_of); Their documention will indicate so explicitly.*/ /*@{*/ -/**Returns whether or not the stream being read is seekable. +/**Returns whether or not the data source being read is seekable. This is true if <ol> <li>The <code><a href="#op_seek_func">seek()</a></code> and @@ -1460,9 +1455,9 @@ int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1); 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 + \return For fully-open seekable sources, 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.*/ + For partially-open or unseekable sources, 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 @@ -1476,7 +1471,7 @@ int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1); \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 + If the source 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); @@ -1493,7 +1488,7 @@ opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); \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 + If the source 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); @@ -1512,9 +1507,9 @@ int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); 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 + of the underlying source if trailing garbage was detected in the file. - \retval #OP_EINVAL The stream is not seekable (so we can't know the length), + \retval #OP_EINVAL The source 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); @@ -1532,7 +1527,7 @@ opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); \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), + \retval #OP_EINVAL The source 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); @@ -1580,8 +1575,8 @@ const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); \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 seekable streams, this is a number between 0 and the value + returned by op_link_count(). 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). @@ -1645,10 +1640,10 @@ ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1); /*@{*/ /**\name Functions for seeking in Opus streams - These functions let you seek in Opus streams, if the underlying stream + These functions let you seek in Opus streams, if the underlying source 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 + individual sources may not be seekable (pipes, live HTTP streams, or HTTP streams from a server that does not support <code>Range</code> requests). op_raw_seek() is the fastest: it is guaranteed to perform at most one @@ -1675,8 +1670,6 @@ ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1); 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 diff --git a/thirdparty/opus/opus_compare.c b/thirdparty/opus/opus_compare.c index 1956e08fa5..06c67d752f 100644 --- a/thirdparty/opus/opus_compare.c +++ b/thirdparty/opus/opus_compare.c @@ -363,9 +363,6 @@ int main(int _argc,const char **_argv){ 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){ diff --git a/thirdparty/opus/opus_decoder.c b/thirdparty/opus/opus_decoder.c index 9113638a00..080bec5072 100644 --- a/thirdparty/opus/opus_decoder.c +++ b/thirdparty/opus/opus_decoder.c @@ -78,26 +78,6 @@ struct OpusDecoder { 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) { @@ -124,7 +104,7 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) return OPUS_BAD_ARG; OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); - /* Initialize SILK decoder */ + /* Initialize SILK encoder */ ret = silk_Get_Decoder_Size(&silkDecSizeBytes); if (ret) return OPUS_INTERNAL_ERROR; @@ -237,7 +217,6 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, int audiosize; int mode; - int bandwidth; int transition=0; int start_band; int redundancy=0; @@ -274,12 +253,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, { 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) { @@ -378,15 +355,15 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, { st->DecControl.nChannelsInternal = st->stream_channels; if( mode == MODE_SILK_ONLY ) { - if( bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { st->DecControl.internalSampleRate = 8000; - } else if( bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { st->DecControl.internalSampleRate = 12000; - } else if( bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { st->DecControl.internalSampleRate = 16000; } else { st->DecControl.internalSampleRate = 16000; - celt_assert( 0 ); + silk_assert( 0 ); } } else { /* Hybrid mode */ @@ -450,26 +427,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, 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) + switch(st->bandwidth) { case OPUS_BANDWIDTH_NARROWBAND: endband = 13; @@ -484,13 +445,24 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, case OPUS_BANDWIDTH_FULLBAND: endband = 21; break; - default: - celt_assert(0); - break; } - MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband))); + celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)); + celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)); + } + + 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); } - 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; @@ -499,21 +471,21 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, /* 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_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))); + 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))); + 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)); + 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); @@ -528,7 +500,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, 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_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); } } @@ -546,18 +518,18 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, { const CELTMode *celt_mode; - MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode))); + 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_decoder_ctl(celt_dec, OPUS_RESET_STATE); + 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))); + 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); } @@ -633,7 +605,6 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, 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 */ @@ -769,7 +740,6 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, 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); @@ -807,7 +777,6 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, 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); @@ -895,7 +864,7 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) goto bad_arg; } if (st->prev_mode == MODE_CELT_ONLY) - ret = celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); else *value = st->DecControl.prevPitchLag; } @@ -922,7 +891,7 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) break; case OPUS_GET_LAST_PACKET_DURATION_REQUEST: { - opus_int32 *value = va_arg(ap, opus_int32*); + opus_uint32 *value = va_arg(ap, opus_uint32*); if (!value) { goto bad_arg; @@ -930,26 +899,6 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) *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; diff --git a/thirdparty/opus/opus_encoder.c b/thirdparty/opus/opus_encoder.c index e98ac5b8d0..9a516a884a 100644 --- a/thirdparty/opus/opus_encoder.c +++ b/thirdparty/opus/opus_encoder.c @@ -53,10 +53,6 @@ #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; @@ -86,7 +82,6 @@ struct OpusEncoder { int encoder_buffer; int lfe; int arch; - int use_dtx; /* general DTX for both SILK and CELT */ #ifndef DISABLE_FLOAT_API TonalityAnalysisState analysis; #endif @@ -102,8 +97,6 @@ struct OpusEncoder { 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; @@ -112,10 +105,7 @@ struct OpusEncoder { 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; }; @@ -123,46 +113,38 @@ struct OpusEncoder { 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 */ + 11000, 1000, /* NB<->MB */ + 14000, 1000, /* MB<->WB */ + 17000, 1000, /* WB<->SWB */ + 21000, 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 */ + 12000, 1000, /* NB<->MB */ + 15000, 1000, /* MB<->WB */ + 18000, 2000, /* WB<->SWB */ + 22000, 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 */ + 11000, 1000, /* NB<->MB */ + 14000, 1000, /* MB<->WB */ + 21000, 2000, /* WB<->SWB */ + 28000, 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 */ + 12000, 1000, /* NB<->MB */ + 18000, 2000, /* MB<->WB */ + 21000, 2000, /* WB<->SWB */ + 30000, 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; +static const opus_int32 stereo_voice_threshold = 30000; +static const opus_int32 stereo_music_threshold = 30000; /* 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 */ + { 64000, 16000}, /* mono */ + { 36000, 16000}, /* stereo */ }; int opus_encoder_get_size(int channels) @@ -263,8 +245,7 @@ int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int applicat st->bandwidth = OPUS_BANDWIDTH_FULLBAND; #ifndef DISABLE_FLOAT_API - tonality_analysis_init(&st->analysis, st->Fs); - st->analysis.application = st->application; + tonality_analysis_init(&st->analysis); #endif return OPUS_OK; @@ -342,11 +323,10 @@ static void silk_biquad_float( } #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) +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) { 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 ); @@ -366,10 +346,9 @@ static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *ou 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 ); + silk_biquad_alt( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_alt( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); } #else silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); @@ -385,17 +364,21 @@ static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *ou int c, i; int shift; - /* Approximates -round(log2(6.3*cutoff_Hz/Fs)) */ - shift=celt_ilog2(Fs/(cutoff_Hz*4)); + /* Approximates -round(log2(4.*cutoff_Hz/Fs)) */ + shift=celt_ilog2(Fs/(cutoff_Hz*3)); for (c=0;c<channels;c++) { for (i=0;i<len;i++) { - opus_val32 x, y; - x = SHL32(EXTEND32(in[channels*i+c]), 14); - y = x-hp_mem[2*c]; + opus_val32 x, tmp, y; + x = SHL32(EXTEND32(in[channels*i+c]), 15); + /* First stage */ + tmp = x-hp_mem[2*c]; hp_mem[2*c] = hp_mem[2*c] + PSHR32(x - hp_mem[2*c], shift); - out[channels*i+c] = EXTRACT16(SATURATE(PSHR32(y, 14), 32767)); + /* Second stage */ + y = tmp - hp_mem[2*c+1]; + hp_mem[2*c+1] = hp_mem[2*c+1] + PSHR32(tmp - hp_mem[2*c+1], shift); + out[channels*i+c] = EXTRACT16(SATURATE(PSHR32(y, 15), 32767)); } } } @@ -403,41 +386,24 @@ static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *ou #else 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 i; - float coef, coef2; - coef = 6.3f*cutoff_Hz/Fs; - coef2 = 1-coef; - if (channels==2) + int c, i; + float coef; + + coef = 4.0f*cutoff_Hz/Fs; + for (c=0;c<channels;c++) { - float m0, m2; - m0 = hp_mem[0]; - m2 = hp_mem[2]; for (i=0;i<len;i++) { - opus_val32 x0, x1, out0, out1; - x0 = in[2*i+0]; - x1 = in[2*i+1]; - out0 = x0-m0; - out1 = x1-m2; - m0 = coef*x0 + VERY_SMALL + coef2*m0; - m2 = coef*x1 + VERY_SMALL + coef2*m2; - out[2*i+0] = out0; - out[2*i+1] = out1; + opus_val32 x, tmp, y; + x = in[channels*i+c]; + /* First stage */ + tmp = x-hp_mem[2*c]; + hp_mem[2*c] = hp_mem[2*c] + coef*(x - hp_mem[2*c]) + VERY_SMALL; + /* Second stage */ + y = tmp - hp_mem[2*c+1]; + hp_mem[2*c+1] = hp_mem[2*c+1] + coef*(tmp - hp_mem[2*c+1]) + VERY_SMALL; + out[channels*i+c] = y; } - hp_mem[0] = m0; - hp_mem[2] = m2; - } else { - float m0; - m0 = hp_mem[0]; - for (i=0;i<len;i++) - { - opus_val32 x, y; - x = in[i]; - y = x-m0; - m0 = coef*x + VERY_SMALL + coef2*m0; - out[i] = y; - } - hp_mem[0] = m0; } } #endif @@ -555,57 +521,287 @@ static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int m } #ifndef DISABLE_FLOAT_API +/* Don't use more than 60 ms for the frame size analysis */ +#define MAX_DYNAMIC_FRAMESIZE 24 +/* Estimates how much the bitrate will be boosted based on the sub-frame energy */ +static float transient_boost(const float *E, const float *E_1, int LM, int maxM) +{ + int i; + int M; + float sumE=0, sumE_1=0; + float metric; + + M = IMIN(maxM, (1<<LM)+1); + for (i=0;i<M;i++) + { + sumE += E[i]; + sumE_1 += E_1[i]; + } + metric = sumE*sumE_1/(M*M); + /*if (LM==3) + printf("%f\n", metric);*/ + /*return metric>10 ? 1 : 0;*/ + /*return MAX16(0,1-exp(-.25*(metric-2.)));*/ + return MIN16(1,(float)sqrt(MAX16(0,.05f*(metric-2)))); +} + +/* Viterbi decoding trying to find the best frame size combination using look-ahead + + State numbering: + 0: unused + 1: 2.5 ms + 2: 5 ms (#1) + 3: 5 ms (#2) + 4: 10 ms (#1) + 5: 10 ms (#2) + 6: 10 ms (#3) + 7: 10 ms (#4) + 8: 20 ms (#1) + 9: 20 ms (#2) + 10: 20 ms (#3) + 11: 20 ms (#4) + 12: 20 ms (#5) + 13: 20 ms (#6) + 14: 20 ms (#7) + 15: 20 ms (#8) +*/ +static int transient_viterbi(const float *E, const float *E_1, int N, int frame_cost, int rate) +{ + int i; + float cost[MAX_DYNAMIC_FRAMESIZE][16]; + int states[MAX_DYNAMIC_FRAMESIZE][16]; + float best_cost; + int best_state; + float factor; + /* Take into account that we damp VBR in the 32 kb/s to 64 kb/s range. */ + if (rate<80) + factor=0; + else if (rate>160) + factor=1; + else + factor = (rate-80.f)/80.f; + /* Makes variable framesize less aggressive at lower bitrates, but I can't + find any valid theoretical justification for this (other than it seems + to help) */ + for (i=0;i<16;i++) + { + /* Impossible state */ + states[0][i] = -1; + cost[0][i] = 1e10; + } + for (i=0;i<4;i++) + { + cost[0][1<<i] = (frame_cost + rate*(1<<i))*(1+factor*transient_boost(E, E_1, i, N+1)); + states[0][1<<i] = i; + } + for (i=1;i<N;i++) + { + int j; + + /* Follow continuations */ + for (j=2;j<16;j++) + { + cost[i][j] = cost[i-1][j-1]; + states[i][j] = j-1; + } + + /* New frames */ + for(j=0;j<4;j++) + { + int k; + float min_cost; + float curr_cost; + states[i][1<<j] = 1; + min_cost = cost[i-1][1]; + for(k=1;k<4;k++) + { + float tmp = cost[i-1][(1<<(k+1))-1]; + if (tmp < min_cost) + { + states[i][1<<j] = (1<<(k+1))-1; + min_cost = tmp; + } + } + curr_cost = (frame_cost + rate*(1<<j))*(1+factor*transient_boost(E+i, E_1+i, j, N-i+1)); + cost[i][1<<j] = min_cost; + /* If part of the frame is outside the analysis window, only count part of the cost */ + if (N-i < (1<<j)) + cost[i][1<<j] += curr_cost*(float)(N-i)/(1<<j); + else + cost[i][1<<j] += curr_cost; + } + } + + best_state=1; + best_cost = cost[N-1][1]; + /* Find best end state (doesn't force a frame to end at N-1) */ + for (i=2;i<16;i++) + { + if (cost[N-1][i]<best_cost) + { + best_cost = cost[N-1][i]; + best_state = i; + } + } + + /* Follow transitions back */ + for (i=N-1;i>=0;i--) + { + /*printf("%d ", best_state);*/ + best_state = states[i][best_state]; + } + /*printf("%d\n", best_state);*/ + return best_state; +} + +static int optimize_framesize(const void *x, int len, int C, opus_int32 Fs, + int bitrate, opus_val16 tonality, float *mem, int buffering, + downmix_func downmix) +{ + int N; + int i; + float e[MAX_DYNAMIC_FRAMESIZE+4]; + float e_1[MAX_DYNAMIC_FRAMESIZE+3]; + opus_val32 memx; + int bestLM=0; + int subframe; + int pos; + int offset; + VARDECL(opus_val32, sub); + + subframe = Fs/400; + ALLOC(sub, subframe, opus_val32); + e[0]=mem[0]; + e_1[0]=1.f/(EPSILON+mem[0]); + if (buffering) + { + /* Consider the CELT delay when not in restricted-lowdelay */ + /* We assume the buffering is between 2.5 and 5 ms */ + offset = 2*subframe - buffering; + celt_assert(offset>=0 && offset <= subframe); + len -= offset; + e[1]=mem[1]; + e_1[1]=1.f/(EPSILON+mem[1]); + e[2]=mem[2]; + e_1[2]=1.f/(EPSILON+mem[2]); + pos = 3; + } else { + pos=1; + offset=0; + } + N=IMIN(len/subframe, MAX_DYNAMIC_FRAMESIZE); + /* Just silencing a warning, it's really initialized later */ + memx = 0; + for (i=0;i<N;i++) + { + float tmp; + opus_val32 tmpx; + int j; + tmp=EPSILON; + + downmix(x, sub, subframe, i*subframe+offset, 0, -2, C); + if (i==0) + memx = sub[0]; + for (j=0;j<subframe;j++) + { + tmpx = sub[j]; + tmp += (tmpx-memx)*(float)(tmpx-memx); + memx = tmpx; + } + e[i+pos] = tmp; + e_1[i+pos] = 1.f/tmp; + } + /* Hack to get 20 ms working with APPLICATION_AUDIO + The real problem is that the corresponding memory needs to use 1.5 ms + from this frame and 1 ms from the next frame */ + e[i+pos] = e[i+pos-1]; + if (buffering) + N=IMIN(MAX_DYNAMIC_FRAMESIZE, N+2); + bestLM = transient_viterbi(e, e_1, N, (int)((1.f+.5f*tonality)*(60*C+40)), bitrate/400); + mem[0] = e[1<<bestLM]; + if (buffering) + { + mem[1] = e[(1<<bestLM)+1]; + mem[2] = e[(1<<bestLM)+2]; + } + return bestLM; +} + +#endif + +#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) +void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C) { const float *x; + opus_val32 scale; int j; - x = (const float *)_x; for (j=0;j<subframe;j++) - y[j] = PCM2VAL(x[(j+offset)*C+c1]); + sub[j] = PCM2VAL(x[(j+offset)*C+c1]); if (c2>-1) { for (j=0;j<subframe;j++) - y[j] += PCM2VAL(x[(j+offset)*C+c2]); + sub[j] += PCM2VAL(x[(j+offset)*C+c2]); } else if (c2==-2) { int c; for (c=1;c<C;c++) { for (j=0;j<subframe;j++) - y[j] += PCM2VAL(x[(j+offset)*C+c]); + sub[j] += PCM2VAL(x[(j+offset)*C+c]); } } +#ifdef FIXED_POINT + scale = (1<<SIG_SHIFT); +#else + scale = 1.f; +#endif + if (C==-2) + scale /= C; + else + scale /= 2; + for (j=0;j<subframe;j++) + sub[j] *= scale; } #endif -void downmix_int(const void *_x, opus_val32 *y, 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) { const opus_int16 *x; + opus_val32 scale; int j; - x = (const opus_int16 *)_x; for (j=0;j<subframe;j++) - y[j] = x[(j+offset)*C+c1]; + sub[j] = x[(j+offset)*C+c1]; if (c2>-1) { for (j=0;j<subframe;j++) - y[j] += x[(j+offset)*C+c2]; + sub[j] += x[(j+offset)*C+c2]; } else if (c2==-2) { int c; for (c=1;c<C;c++) { for (j=0;j<subframe;j++) - y[j] += x[(j+offset)*C+c]; + sub[j] += x[(j+offset)*C+c]; } } +#ifdef FIXED_POINT + scale = (1<<SIG_SHIFT); +#else + scale = 1.f/32768; +#endif + if (C==-2) + scale /= C; + else + scale /= 2; + for (j=0;j<subframe;j++) + sub[j] *= scale; } opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs) @@ -615,24 +811,53 @@ opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_ return -1; if (variable_duration == OPUS_FRAMESIZE_ARG) new_size = frame_size; - else if (variable_duration >= 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 if (variable_duration == OPUS_FRAMESIZE_VARIABLE) + new_size = Fs/50; + else if (variable_duration >= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_60_MS) + new_size = IMIN(3*Fs/50, (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS)); else return -1; if (new_size>frame_size) return -1; - if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs && - 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs && - 50*new_size!=4*Fs && 50*new_size!=5*Fs && 50*new_size!=6*Fs) + if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs && + 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs) return -1; return new_size; } +opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size, + int variable_duration, int C, opus_int32 Fs, int bitrate_bps, + int delay_compensation, downmix_func downmix +#ifndef DISABLE_FLOAT_API + , float *subframe_mem +#endif + ) +{ +#ifndef DISABLE_FLOAT_API + if (variable_duration == OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs/200) + { + int LM = 3; + LM = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps, + 0, subframe_mem, delay_compensation, downmix); + while ((Fs/400<<LM)>frame_size) + LM--; + frame_size = (Fs/400<<LM); + } else +#else + (void)analysis_pcm; + (void)C; + (void)bitrate_bps; + (void)delay_compensation; + (void)downmix; +#endif + { + frame_size = frame_size_select(frame_size, variable_duration, Fs); + } + if (frame_size<0) + return -1; + return frame_size; +} + opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem) { opus_val32 xx, xy, yy; @@ -679,12 +904,6 @@ opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int3 xy += SHR32(pxy, 10); yy += SHR32(pyy, 10); } -#ifndef FIXED_POINT - if (!(xx < 1e9f) || celt_isnan(xx) || !(yy < 1e9f) || celt_isnan(yy)) - { - xy = xx = yy = 0; - } -#endif mem->XX += 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); @@ -715,354 +934,6 @@ opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int3 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<N;i++) - { - if (rate_table[i][0] > 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<len; i++) - energy += SHR32(MULT16_16(pcm[i], pcm[i]), shift); - - /* Normalize energy by the frame size and left-shift back to the original position */ - energy /= len; - energy = SHL32(energy, shift); - - return energy; -} -#else -static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, int channels, int arch) -{ - int len = frame_size*channels; - return celt_inner_prod(pcm, pcm, len, arch)/len; -} -#endif - -/* Decides if DTX should be turned on (=1) or off (=0) */ -static int decide_dtx_mode(float activity_probability, /* probability that current frame contains speech/music */ - int *nb_no_activity_frames, /* number of consecutive frames with no activity */ - opus_val32 peak_signal_energy, /* peak energy of desired signal detected so far */ - const opus_val16 *pcm, /* input pcm signal */ - int frame_size, /* frame size */ - int channels, - int is_silence, /* only digital silence detected in this frame */ - int arch - ) -{ - opus_val32 noise_energy; - - if (!is_silence) - { - if (activity_probability < DTX_ACTIVITY_THRESHOLD) /* is noise */ - { - noise_energy = compute_frame_energy(pcm, frame_size, channels, arch); - - /* but is sufficiently quiet */ - is_silence = peak_signal_energy >= (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;i<nb_frames;i++) - { - st->silk_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, @@ -1100,7 +971,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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); @@ -1109,19 +979,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ max_data_bytes = IMIN(1276, out_data_bytes); st->rangeFinal = 0; - if (frame_size <= 0 || max_data_bytes <= 0) + if ((!st->variable_duration && 400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs && + 50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs) + || (400*frame_size < st->Fs) + || 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) @@ -1135,55 +1001,31 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ #ifndef DISABLE_FLOAT_API analysis_info.valid = 0; #ifdef FIXED_POINT - if (st->silk_mode.complexity >= 10 && st->Fs>=16000) + if (st->silk_mode.complexity >= 10 && st->Fs==48000) #else - if (st->silk_mode.complexity >= 7 && st->Fs>=16000) + if (st->silk_mode.complexity >= 7 && st->Fs==48000) #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->voice_ratio = -1; +#ifndef DISABLE_FLOAT_API 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)); - } + st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob)); analysis_bandwidth = analysis_info.bandwidth; if (analysis_bandwidth<=12) @@ -1197,8 +1039,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ else st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; } -#else - st->voice_ratio = -1; #endif if (st->channels==2 && st->force_channels!=1) @@ -1212,13 +1052,12 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (!st->use_vbr) { int cbrBytes; - /* Multiply by 12 to make sure the division is exact. */ - int frame_rate12 = 12*st->Fs/frame_size; + /* Multiply by 3 to make sure the division is exact. */ + int frame_rate3 = 3*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); + cbrBytes = IMIN( (3*st->bitrate_bps/8 + frame_rate3/2)/frame_rate3, max_data_bytes); + st->bitrate_bps = cbrBytes*(opus_int32)frame_rate3*8/3; + max_data_bytes = 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))) @@ -1226,63 +1065,25 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /*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 (frame_rate < 50) + tocmode = MODE_SILK_ONLY; 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; - + ret = 1; 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; @@ -1290,8 +1091,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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); + equiv_rate = st->bitrate_bps - (40*st->channels+20)*(st->Fs/frame_size - 50); if (st->signal_type == OPUS_SIGNAL_VOICE) voice_est = 127; @@ -1332,17 +1132,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } #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 + equiv_rate = st->bitrate_bps - (40*st->stream_channels+20)*(st->Fs/frame_size - 50); /* Mode selection depending on application and signal type */ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) @@ -1391,15 +1181,10 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* 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. */ + /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */ 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; } @@ -1409,6 +1194,19 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ st->mode = MODE_CELT_ONLY; if (st->lfe) st->mode = MODE_CELT_ONLY; + /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + + 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; + } if (st->prev_mode > 0 && ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || @@ -1428,22 +1226,23 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } } } - - /* 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) + /* For the first frame at a new SILK bandwidth */ + if (st->silk_bw_switch) { - /* 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; + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + prefill=1; } - /* 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 (redundancy) + { + /* Fair share of the max size allowed */ + redundancy_bytes = IMIN(257, max_data_bytes*(opus_int32)(st->Fs/200)/(frame_size+st->Fs/200)); + /* For VBR, target the actual bitrate (subject to the limit above) */ + if (st->use_vbr) + redundancy_bytes = IMIN(redundancy_bytes, st->bitrate_bps/1600); + } if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) { @@ -1458,7 +1257,17 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; opus_int32 bandwidth_thresholds[8]; int bandwidth = OPUS_BANDWIDTH_FULLBAND; + opus_int32 equiv_rate2; + equiv_rate2 = equiv_rate; + if (st->mode != MODE_CELT_ONLY) + { + /* Adjust the threshold +/- 10% depending on complexity */ + equiv_rate2 = equiv_rate2 * (45+st->silk_mode.complexity)/50; + /* CBR is less efficient by ~1 kb/s */ + if (!st->use_vbr) + equiv_rate2 -= 1000; + } if (st->channels==2 && st->force_channels!=1) { voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; @@ -1479,19 +1288,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; if (!st->first) { - if (st->auto_bandwidth >= bandwidth) + if (st->bandwidth >= bandwidth) threshold -= hysteresis; else threshold += hysteresis; } - if (equiv_rate >= threshold) + if (equiv_rate2 >= 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; + st->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) @@ -1544,8 +1349,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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 */ @@ -1554,34 +1357,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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) + /* Can't support higher than wideband for >20 ms frames */ + if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)) { - int enc_frame_size; + VARDECL(unsigned char, tmp_data); 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; + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + VARDECL(OpusRepacketizer, rp); + opus_int32 bytes_per_frame; + opus_int32 repacketize_len; #ifndef DISABLE_FLOAT_API if (analysis_read_pos_bak!= -1) @@ -1591,34 +1375,74 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } #endif - ret = encode_multiframe_packet(st, pcm, nb_frames, enc_frame_size, data, - out_data_bytes, to_celt, lsb_depth, float_api); + nb_frames = frame_size > st->Fs/25 ? 3 : 2; + bytes_per_frame = IMIN(1276,(out_data_bytes-3)/nb_frames); - RESTORE_STACK; - return ret; - } + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); - /* 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; - } + ALLOC(rp, 1, OpusRepacketizer); + opus_repacketizer_init(rp); - /* 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; + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; - if (redundancy) - { - redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); - if (redundancy_bytes == 0) - redundancy = 0; + 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;i<nb_frames;i++) + { + int tmp_len; + st->silk_mode.toMono = 0; + /* 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*st->Fs/50), st->Fs/50, + tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, + NULL, 0, c1, c2, analysis_channels, downmix, 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; + } + } + if (st->use_vbr) + repacketize_len = out_data_bytes; + else + repacketize_len = IMIN(3*st->bitrate_bps/(3*8*50/nb_frames), out_data_bytes); + 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; + } + 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; } + 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; /* 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; @@ -1643,7 +1467,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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); + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); } else { dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); } @@ -1668,7 +1492,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_CELT_ONLY) { opus_int32 total_bitRate, celt_rate; - opus_int activity; #ifdef FIXED_POINT const opus_int16 *pcm_silk; #else @@ -1676,26 +1499,30 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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 ) { + int HB_gain_ref; /* 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); + st->silk_mode.bitRate = st->stream_channels * ( 5000 + 1000 * ( st->Fs == 100 * frame_size ) ); + if( curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND ) { + /* SILK gets 2/3 of the remaining bits */ + st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 2 / 3; + } else { /* FULLBAND */ + /* SILK gets 3/5 of the remaining bits */ + st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 3 / 5; + } + /* Don't let SILK use more than 80% */ + if( st->silk_mode.bitRate > total_bitRate * 4/5 ) { + st->silk_mode.bitRate = total_bitRate * 4/5; + } 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); + HB_gain_ref = (curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND) ? 3000 : 3600; + HB_gain = SHL32((opus_val32)celt_rate, 9) / SHR32((opus_val32)celt_rate + st->stream_channels * HB_gain_ref, 6); + HB_gain = HB_gain < (opus_val32)Q15ONE*6/7 ? HB_gain + Q15ONE/7 : Q15ONE; } } else { /* SILK gets all bits */ @@ -1742,6 +1569,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ st->silk_mode.bitRate += 3*rate_offset/5; else st->silk_mode.bitRate += rate_offset; + bytes_target += rate_offset * frame_size / (8 * st->Fs); } st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; @@ -1752,7 +1580,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { st->silk_mode.desiredInternalSampleRate = 12000; } else { - celt_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + silk_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); st->silk_mode.desiredInternalSampleRate = 16000; } if( st->mode == MODE_HYBRID ) { @@ -1762,53 +1590,40 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ st->silk_mode.minInternalSampleRate = 8000; } - st->silk_mode.maxInternalSampleRate = 16000; if (st->mode == MODE_SILK_ONLY) { opus_int32 effective_max_rate = max_rate; + st->silk_mode.maxInternalSampleRate = 16000; if (frame_rate > 50) effective_max_rate = effective_max_rate*2/3; - if (effective_max_rate < 8000) + if (effective_max_rate < 13000) { st->silk_mode.maxInternalSampleRate = 12000; st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); } - if (effective_max_rate < 7000) + if (effective_max_rate < 9600) { st->silk_mode.maxInternalSampleRate = 8000; st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); } + } else { + st->silk_mode.maxInternalSampleRate = 16000; } st->silk_mode.useCBR = !st->use_vbr; /* Call SILK encoder for the low band */ + nBytes = IMIN(1275, max_data_bytes-1-redundancy_bytes); - /* 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; - } + st->silk_mode.maxBits = nBytes*8; + /* Only allow up to 90% of the bits for hybrid mode*/ + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10; 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; - } + st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8; + /* Reduce the initial target to make it easier to reach the CBR rate */ + st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000); } if (prefill) @@ -1831,9 +1646,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ for (i=0;i<st->encoder_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; + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 ); } #ifdef FIXED_POINT @@ -1842,14 +1655,20 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ for (i=0;i<frame_size*st->channels;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 ); + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 ); if( ret ) { /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ /* Handle error */ RESTORE_STACK; return OPUS_INTERNAL_ERROR; } - + 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; + } /* Extract SILK internal bandwidth for signaling in first byte */ if( st->mode == MODE_SILK_ONLY ) { if( st->silk_mode.internalSampleRate == 8000 ) { @@ -1860,24 +1679,14 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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; + silk_assert( st->silk_mode.internalSampleRate == 16000 ); } + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady; /* 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); + redundancy = 1; celt_to_silk = 0; st->silk_bw_switch = 1; } @@ -1918,18 +1727,40 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode == MODE_HYBRID) { + int len; + + len = (ec_tell(&enc)+7)>>3; + if (redundancy) + len += st->mode == MODE_HYBRID ? 3 : 1; 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)); + nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs); + } else { + /* check if SILK used up too much */ + nb_compr_bytes = len > bytes_target ? len : bytes_target; } } else { if (st->use_vbr) { + opus_int32 bonus=0; +#ifndef DISABLE_FLOAT_API + if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != st->Fs/50) + { + bonus = (60*st->stream_channels+40)*(st->Fs/frame_size-50); + if (analysis_info.valid) + bonus = (opus_int32)(bonus*(1.f+.5f*analysis_info.tonality)); + } +#endif 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)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps+bonus)); + nb_compr_bytes = max_data_bytes-1-redundancy_bytes; + } else { + nb_compr_bytes = bytes_target; } } + + } else { + nb_compr_bytes = 0; } ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); @@ -1955,14 +1786,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } 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); - } + st->silk_mode.stereoWidth_Q14 = IMIN((1<<14),2*IMAX(0,equiv_rate-30000)); 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) ) { @@ -1985,23 +1809,19 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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) + if (st->mode == MODE_HYBRID && (redundancy || ec_tell(&enc)+37 <= 8*nb_compr_bytes)) 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); - } + max_redundancy = (max_data_bytes-1)-nb_compr_bytes; 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(max_redundancy, st->bitrate_bps/1600); redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); if (st->mode == MODE_HYBRID) ec_enc_uint(&enc, redundancy_bytes-2, 256); @@ -2023,7 +1843,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ ec_enc_done(&enc); nb_compr_bytes = ret; } else { - nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; + nb_compr_bytes = IMIN((max_data_bytes-1)-redundancy_bytes, nb_compr_bytes); ec_enc_shrink(&enc, nb_compr_bytes); } @@ -2031,12 +1851,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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) @@ -2044,7 +1858,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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) { @@ -2068,25 +1881,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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 false, we already busted the budget and we'll end up with a "PLC packet" */ 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; - } } } @@ -2102,15 +1905,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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); @@ -2140,23 +1935,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ 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) @@ -2184,6 +1962,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (!st->use_vbr) { if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK) + { RESTORE_STACK; return OPUS_INTERNAL_ERROR; @@ -2202,15 +1981,18 @@ opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_fra { int i, ret; int frame_size; + int delay_compensation; 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; - } + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + frame_size = compute_frame_size(pcm, analysis_frame_size, + st->variable_duration, st->channels, st->Fs, st->bitrate_bps, + delay_compensation, downmix_float, st->analysis.subframe_mem); + ALLOC(in, frame_size*st->channels, opus_int16); for (i=0;i<frame_size*st->channels;i++) @@ -2226,7 +2008,18 @@ opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_fram unsigned char *data, opus_int32 out_data_bytes) { int frame_size; - frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + int delay_compensation; + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + frame_size = compute_frame_size(pcm, analysis_frame_size, + st->variable_duration, st->channels, st->Fs, st->bitrate_bps, + delay_compensation, downmix_int +#ifndef DISABLE_FLOAT_API + , st->analysis.subframe_mem +#endif + ); return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); } @@ -2237,15 +2030,18 @@ opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_fram { int i, ret; int frame_size; + int delay_compensation; 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; - } + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + frame_size = compute_frame_size(pcm, analysis_frame_size, + st->variable_duration, st->channels, st->Fs, st->bitrate_bps, + delay_compensation, downmix_int, st->analysis.subframe_mem); + ALLOC(in, frame_size*st->channels, float); for (i=0;i<frame_size*st->channels;i++) @@ -2259,7 +2055,14 @@ opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_fra unsigned char *data, opus_int32 out_data_bytes) { int frame_size; - frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + int delay_compensation; + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + frame_size = compute_frame_size(pcm, analysis_frame_size, + st->variable_duration, st->channels, st->Fs, st->bitrate_bps, + delay_compensation, downmix_float, st->analysis.subframe_mem); return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); } @@ -2290,9 +2093,6 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) break; } st->application = value; -#ifndef DISABLE_FLOAT_API - st->analysis.application = value; -#endif } break; case OPUS_GET_APPLICATION_REQUEST: @@ -2411,7 +2211,7 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) { goto bad_arg; } - st->use_dtx = value; + st->silk_mode.useDTX = value; } break; case OPUS_GET_DTX_REQUEST: @@ -2421,7 +2221,7 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) { goto bad_arg; } - *value = st->use_dtx; + *value = st->silk_mode.useDTX; } break; case OPUS_SET_COMPLEXITY_REQUEST: @@ -2622,15 +2422,15 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) 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) + 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_VARIABLE) { goto bad_arg; } st->variable_duration = value; + celt_encoder_ctl(celt_enc, OPUS_SET_EXPERT_FRAME_DURATION(value)); } break; case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: @@ -2659,26 +2459,6 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) *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; @@ -2727,33 +2507,6 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) 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;n<st->silk_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: { diff --git a/thirdparty/opus/opus_multistream_decoder.c b/thirdparty/opus/opus_multistream_decoder.c index 0018517aeb..b95eaa6eac 100644 --- a/thirdparty/opus/opus_multistream_decoder.c +++ b/thirdparty/opus/opus_multistream_decoder.c @@ -37,19 +37,16 @@ #include "float_cast.h" #include "os_support.h" -/* DECODER */ +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; -#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 + +/* DECODER */ + opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) { int coupled_size; @@ -146,6 +143,15 @@ OpusMSDecoder *opus_multistream_decoder_create( return st; } +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 +); + static int opus_multistream_packet_validate(const unsigned char *data, opus_int32 len, int nb_streams, opus_int32 Fs) { @@ -175,7 +181,7 @@ static int opus_multistream_packet_validate(const unsigned char *data, return samples; } -int opus_multistream_decode_native( +static int opus_multistream_decode_native( OpusMSDecoder *st, const unsigned char *data, opus_int32 len, @@ -183,8 +189,7 @@ int opus_multistream_decode_native( opus_copy_channel_out_func copy_channel_out, int frame_size, int decode_fec, - int soft_clip, - void *user_data + int soft_clip ) { opus_int32 Fs; @@ -196,14 +201,8 @@ int opus_multistream_decode_native( VARDECL(opus_val16, buf); ALLOC_STACK; - VALIDATE_MS_DECODER(st); - if (frame_size <= 0) - { - RESTORE_STACK; - return OPUS_BAD_ARG; - } /* Limit frame_size to avoid excessive stack allocations. */ - MUST_SUCCEED(opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs))); + opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs)); frame_size = IMIN(frame_size, Fs/25*3); ALLOC(buf, 2*frame_size, opus_val16); ptr = (char*)st + align(sizeof(OpusMSDecoder)); @@ -238,8 +237,7 @@ int opus_multistream_decode_native( for (s=0;s<st->layout.nb_streams;s++) { OpusDecoder *dec; - opus_int32 packet_offset; - int ret; + int packet_offset, ret; dec = (OpusDecoder*)ptr; ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); @@ -267,7 +265,7 @@ int opus_multistream_decode_native( 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); + buf, 2, frame_size); prev = chan; } prev = -1; @@ -275,7 +273,7 @@ int opus_multistream_decode_native( 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); + buf+1, 2, frame_size); prev = chan; } } else { @@ -285,7 +283,7 @@ int opus_multistream_decode_native( 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); + buf, 1, frame_size); prev = chan; } } @@ -296,7 +294,7 @@ int opus_multistream_decode_native( if (st->layout.mapping[c] == 255) { (*copy_channel_out)(pcm, st->layout.nb_channels, c, - NULL, 0, frame_size, user_data); + NULL, 0, frame_size); } } RESTORE_STACK; @@ -310,13 +308,11 @@ static void opus_copy_channel_out_float( int dst_channel, const opus_val16 *src, int src_stride, - int frame_size, - void *user_data + int frame_size ) { float *float_dst; opus_int32 i; - (void)user_data; float_dst = (float*)dst; if (src != NULL) { @@ -341,13 +337,11 @@ static void opus_copy_channel_out_short( int dst_channel, const opus_val16 *src, int src_stride, - int frame_size, - void *user_data + int frame_size ) { opus_int16 *short_dst; opus_int32 i; - (void)user_data; short_dst = (opus_int16*)dst; if (src != NULL) { @@ -378,7 +372,7 @@ int opus_multistream_decode( ) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0, NULL); + pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0); } #ifndef DISABLE_FLOAT_API @@ -386,7 +380,7 @@ int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data, opus_int32 len, float *pcm, int frame_size, int decode_fec) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); + pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); } #endif @@ -396,30 +390,32 @@ int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data, opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1, NULL); + pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1); } int opus_multistream_decode_float( OpusMSDecoder *st, const unsigned char *data, opus_int32 len, - opus_val16 *pcm, + float *pcm, int frame_size, int decode_fec ) { return opus_multistream_decode_native(st, data, len, - pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL); + pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0); } #endif -int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, - va_list ap) +int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) { + va_list ap; int coupled_size, mono_size; char *ptr; int ret = OPUS_OK; + va_start(ap, request); + coupled_size = opus_decoder_get_size(2); mono_size = opus_decoder_get_size(1); ptr = (char*)st + align(sizeof(OpusMSDecoder)); @@ -429,7 +425,6 @@ int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, case OPUS_GET_SAMPLE_RATE_REQUEST: case OPUS_GET_GAIN_REQUEST: case OPUS_GET_LAST_PACKET_DURATION_REQUEST: - case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: { OpusDecoder *dec; /* For int32* GET params, just query the first stream */ @@ -487,7 +482,7 @@ int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, OpusDecoder **value; stream_id = va_arg(ap, opus_int32); if (stream_id<0 || stream_id >= st->layout.nb_streams) - goto bad_arg; + ret = OPUS_BAD_ARG; value = va_arg(ap, OpusDecoder**); if (!value) { @@ -504,7 +499,6 @@ int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, } break; case OPUS_SET_GAIN_REQUEST: - case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: { int s; /* This works for int32 params */ @@ -528,20 +522,14 @@ int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request, ret = OPUS_UNIMPLEMENTED; break; } + + va_end(ap); return ret; bad_arg: + va_end(ap); 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) { diff --git a/thirdparty/opus/opus_multistream_encoder.c b/thirdparty/opus/opus_multistream_encoder.c index 93204a14c1..1698223a16 100644 --- a/thirdparty/opus/opus_multistream_encoder.c +++ b/thirdparty/opus/opus_multistream_encoder.c @@ -61,6 +61,38 @@ static const VorbisLayout vorbis_mappings[8] = { {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */ }; +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 +); + +typedef enum { + MAPPING_TYPE_NONE, + MAPPING_TYPE_SURROUND +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + , /* Do not include comma at end of enumerator list */ + MAPPING_TYPE_AMBISONICS +#endif +} MappingType; + +struct OpusMSEncoder { + ChannelLayout layout; + int arch; + int lfe_stream; + int application; + int variable_duration; + MappingType mapping_type; + opus_int32 bitrate_bps; + float subframe_mem[3]; + /* Encoder states go here */ + /* then opus_val32 window_mem[channels*120]; */ + /* then opus_val32 preemph_mem[channels]; */ +}; + static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) { int s; @@ -101,29 +133,6 @@ static opus_val32 *ms_get_window_mem(OpusMSEncoder *st) 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; @@ -231,7 +240,6 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b 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]; @@ -242,7 +250,6 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b upsample = resampling_factor(rate); frame_size = len*upsample; - freq_size = IMIN(960, frame_size); /* LM = log2(frame_size / 120) */ for (LM=0;LM<celt_mode->maxLM;LM++) @@ -251,7 +258,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b ALLOC(in, frame_size+overlap, opus_val32); ALLOC(x, len, opus_val16); - ALLOC(freq, freq_size, opus_val32); + ALLOC(freq, frame_size, opus_val32); channel_pos(channels, pos); @@ -261,11 +268,8 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b for (c=0;c<channels;c++) { - int frame; - int nb_frames = frame_size/freq_size; - celt_assert(nb_frames*freq_size == frame_size); OPUS_COPY(in, mem+c*overlap, overlap); - (*copy_channel_in)(x, 1, pcm, channels, c, len, NULL); + (*copy_channel_in)(x, 1, pcm, channels, c, len); celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0); #ifndef FIXED_POINT { @@ -280,26 +284,18 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b } } #endif - OPUS_CLEAR(bandE, 21); - for (frame=0;frame<nb_frames;frame++) + clt_mdct_forward(&celt_mode->mdct, in, freq, celt_mode->window, + overlap, celt_mode->maxLM-LM, 1, arch); + if (upsample != 1) { - opus_val32 tmpE[21]; - clt_mdct_forward(&celt_mode->mdct, 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<bound;i++) - freq[i] *= upsample; - for (;i<freq_size;i++) - freq[i] = 0; - } - - compute_band_energies(celt_mode, freq, tmpE, 21, 1, LM, arch); - /* If we have multiple frames, take the max energy. */ - for (i=0;i<21;i++) - bandE[i] = MAX32(bandE[i], tmpE[i]); + int bound = len; + for (i=0;i<bound;i++) + freq[i] *= upsample; + for (;i<frame_size;i++) + freq[i] = 0; } + + compute_band_energies(celt_mode, freq, bandE, 21, 1, LM); amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1); /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */ for (i=1;i<21;i++) @@ -412,10 +408,12 @@ opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_ { nb_streams=channels; nb_coupled_streams=0; - } else if (mapping_family==2) +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + } else if (mapping_family==254) { - if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams)) - return 0; + nb_streams=channels; + nb_coupled_streams=0; +#endif } else return 0; size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); @@ -450,6 +448,7 @@ static int opus_multistream_encoder_init_impl( st->layout.nb_channels = channels; st->layout.nb_streams = streams; st->layout.nb_coupled_streams = coupled_streams; + st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0; if (mapping_type != MAPPING_TYPE_SURROUND) st->lfe_stream = -1; st->bitrate_bps = OPUS_AUTO; @@ -457,13 +456,7 @@ static int opus_multistream_encoder_init_impl( st->variable_duration = OPUS_FRAMESIZE_ARG; for (i=0;i<st->layout.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)) + if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout)) return OPUS_BAD_ARG; ptr = (char*)st + align(sizeof(OpusMSEncoder)); coupled_size = opus_encoder_get_size(2); @@ -556,23 +549,25 @@ int opus_multistream_surround_encoder_init( *coupled_streams=0; for(i=0;i<channels;i++) mapping[i] = i; - } else if (mapping_family==2) +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + } else if (mapping_family==254) { int i; - if (!validate_ambisonics(channels, streams, coupled_streams)) - return OPUS_BAD_ARG; - for(i = 0; i < (*streams - *coupled_streams); i++) - mapping[i] = i + (*coupled_streams * 2); - for(i = 0; i < *coupled_streams * 2; i++) - mapping[i + (*streams - *coupled_streams)] = i; + *streams=channels; + *coupled_streams=0; + for(i=0;i<channels;i++) + mapping[i] = i; +#endif } else return OPUS_UNIMPLEMENTED; if (channels>2 && mapping_family==1) { mapping_type = MAPPING_TYPE_SURROUND; - } else if (mapping_family==2) +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS + } else if (mapping_family==254) { mapping_type = MAPPING_TYPE_AMBISONICS; +#endif } else { mapping_type = MAPPING_TYPE_NONE; @@ -677,62 +672,62 @@ static void surround_rate_allocation( 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 > st->layout.nb_channels*40000) + stream_offset = 20000; + else + stream_offset = st->bitrate_bps/st->layout.nb_channels/2; + stream_offset += 60*(Fs/frame_size-50); + /* We start by giving each stream (coupled or uncoupled) the same bitrate. + This models the main saving of coupled channels over uncoupled. */ + /* The LFE stream is an exception to the above and gets fewer bits. */ + lfe_offset = 3500 + 60*(Fs/frame_size-50); + /* Coupled streams get twice the mono rate after the first 20 kb/s. */ + coupled_ratio = 512; + /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */ + lfe_ratio = 32; + + /* Compute bitrate allocation between streams */ if (st->bitrate_bps==OPUS_AUTO) { - bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe; + channel_rate = Fs+60*Fs/frame_size; } else if (st->bitrate_bps==OPUS_BITRATE_MAX) { - bitrate = nb_normal*300000 + nb_lfe*128000; + channel_rate = 300000; } else { - bitrate = st->bitrate_bps; + int nb_lfe; + int nb_uncoupled; + int nb_coupled; + 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; + total = (nb_uncoupled<<8) /* mono */ + + coupled_ratio*nb_coupled /* stereo */ + + nb_lfe*lfe_ratio; + channel_rate = 256*(st->bitrate_bps-lfe_offset*nb_lfe-stream_offset*(nb_coupled+nb_uncoupled))/total; } - - /* 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; +#ifndef FIXED_POINT + if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50) + { + opus_int32 bonus; + bonus = 60*(Fs/frame_size-50); + channel_rate += bonus; + } +#endif for (i=0;i<st->layout.nb_streams;i++) { if (i<st->layout.nb_coupled_streams) - rate[i] = 2*channel_offset + IMAX(0, stream_offset+(channel_rate*coupled_ratio>>8)); + rate[i] = stream_offset+(channel_rate*coupled_ratio>>8); else if (i!=st->lfe_stream) - rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate); + rate[i] = stream_offset+channel_rate; else - rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8)); + rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8); } } +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS static void ambisonics_rate_allocation( OpusMSEncoder *st, opus_int32 *rate, @@ -741,31 +736,50 @@ static void ambisonics_rate_allocation( ) { int i; - opus_int32 total_rate; - opus_int32 per_stream_rate; + int non_mono_rate; + int total_rate; - const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams; + /* The mono channel gets (rate_ratio_num / rate_ratio_den) times as many bits + * as all other channels */ + const int rate_ratio_num = 4; + const int rate_ratio_den = 3; + const int num_channels = st->layout.nb_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; + total_rate = num_channels * (20000 + st->layout.nb_streams*(Fs+60*Fs/frame_size)); } else if (st->bitrate_bps==OPUS_BITRATE_MAX) { - total_rate = nb_channels * 320000; - } else - { + total_rate = num_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++) + /* Let y be the non-mono rate and let p, q be integers such that the mono + * channel rate is (p/q) * y. + * Also let T be the total bitrate to allocate. Then + * (n - 1) y + (p/q) y = T + * y = (T q) / (qn - q + p) + */ + non_mono_rate = + total_rate * rate_ratio_den + / (rate_ratio_den*num_channels + rate_ratio_num - rate_ratio_den); + +#ifndef FIXED_POINT + if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50) { - rate[i] = per_stream_rate; + opus_int32 bonus = 60*(Fs/frame_size-50); + non_mono_rate += bonus; + } +#endif + + rate[0] = total_rate - (num_channels - 1) * non_mono_rate; + for (i=1;i<st->layout.nb_streams;i++) + { + rate[i] = non_mono_rate; } } +#endif /* ENABLE_EXPERIMENTAL_AMBISONICS */ static opus_int32 rate_allocation( OpusMSEncoder *st, @@ -781,9 +795,11 @@ static opus_int32 rate_allocation( ptr = (char*)st + align(sizeof(OpusMSEncoder)); opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { ambisonics_rate_allocation(st, rate, frame_size, Fs); } else +#endif { surround_rate_allocation(st, rate, frame_size, Fs); } @@ -796,9 +812,9 @@ static opus_int32 rate_allocation( 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 +/* Max size in case the encoder decides to return three frames */ +#define MS_FRAME_TMP (3*1275+7) +static int opus_multistream_encode_native ( OpusMSEncoder *st, opus_copy_channel_in_func copy_channel_in, @@ -808,8 +824,7 @@ int opus_multistream_encode_native opus_int32 max_data_bytes, int lsb_depth, downmix_func downmix, - int float_api, - void *user_data + int float_api ) { opus_int32 Fs; @@ -844,8 +859,32 @@ int opus_multistream_encode_native 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) + { + opus_int32 delay_compensation; + int channels; + + channels = st->layout.nb_streams + st->layout.nb_coupled_streams; + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation)); + delay_compensation -= Fs/400; + frame_size = compute_frame_size(pcm, analysis_frame_size, + st->variable_duration, channels, Fs, st->bitrate_bps, + delay_compensation, downmix +#ifndef DISABLE_FLOAT_API + , st->subframe_mem +#endif + ); + } + + if (400*frame_size < Fs) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + /* Validate frame_size before using it to allocate stack space. + This mirrors the checks in opus_encode[_float](). */ + if (400*frame_size != Fs && 200*frame_size != Fs && + 100*frame_size != Fs && 50*frame_size != Fs && + 25*frame_size != Fs && 50*frame_size != 3*Fs) { RESTORE_STACK; return OPUS_BAD_ARG; @@ -853,9 +892,6 @@ int opus_multistream_encode_native /* 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; @@ -916,9 +952,11 @@ int opus_multistream_encode_native opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); } } +#ifdef ENABLE_EXPERIMENTAL_AMBISONICS else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); } +#endif } ptr = (char*)st + align(sizeof(OpusMSEncoder)); @@ -941,9 +979,9 @@ int opus_multistream_encode_native 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); + pcm, st->layout.nb_channels, left, frame_size); (*copy_channel_in)(buf+1, 2, - pcm, st->layout.nb_channels, right, frame_size, user_data); + pcm, st->layout.nb_channels, right, frame_size); ptr += align(coupled_size); if (st->mapping_type == MAPPING_TYPE_SURROUND) { @@ -959,7 +997,7 @@ int opus_multistream_encode_native 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); + pcm, st->layout.nb_channels, chan, frame_size); ptr += align(mono_size); if (st->mapping_type == MAPPING_TYPE_SURROUND) { @@ -975,9 +1013,6 @@ int opus_multistream_encode_native 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; @@ -1018,13 +1053,11 @@ static void opus_copy_channel_in_float( const void *src, int src_stride, int src_channel, - int frame_size, - void *user_data + int frame_size ) { const float *float_src; opus_int32 i; - (void)user_data; float_src = (const float *)src; for (i=0;i<frame_size;i++) #if defined(FIXED_POINT) @@ -1041,13 +1074,11 @@ static void opus_copy_channel_in_short( const void *src, int src_stride, int src_channel, - int frame_size, - void *user_data + int frame_size ) { const opus_int16 *short_src; opus_int32 i; - (void)user_data; short_src = (const opus_int16 *)src; for (i=0;i<frame_size;i++) #if defined(FIXED_POINT) @@ -1068,7 +1099,7 @@ int opus_multistream_encode( ) { return opus_multistream_encode_native(st, opus_copy_channel_in_short, - pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL); + pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0); } #ifndef DISABLE_FLOAT_API @@ -1081,7 +1112,7 @@ int opus_multistream_encode_float( ) { return opus_multistream_encode_native(st, opus_copy_channel_in_float, - pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1, NULL); + pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1); } #endif @@ -1097,7 +1128,7 @@ int opus_multistream_encode_float ) { return opus_multistream_encode_native(st, opus_copy_channel_in_float, - pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1, NULL); + pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1); } int opus_multistream_encode( @@ -1109,17 +1140,19 @@ int opus_multistream_encode( ) { return opus_multistream_encode_native(st, opus_copy_channel_in_short, - pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL); + pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0); } #endif -int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request, - va_list ap) +int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) { + va_list ap; int coupled_size, mono_size; char *ptr; int ret = OPUS_OK; + va_start(ap, request); + coupled_size = opus_encoder_get_size(2); mono_size = opus_encoder_get_size(1); ptr = (char*)st + align(sizeof(OpusMSEncoder)); @@ -1128,11 +1161,9 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request, case OPUS_SET_BITRATE_REQUEST: { opus_int32 value = va_arg(ap, opus_int32); - if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX) { - if (value <= 0) - goto bad_arg; - value = IMIN(300000*st->layout.nb_channels, IMAX(500*st->layout.nb_channels, value)); + goto bad_arg; } st->bitrate_bps = value; } @@ -1175,7 +1206,6 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int 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 */ @@ -1222,7 +1252,6 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int 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 */ @@ -1249,7 +1278,7 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request, OpusEncoder **value; stream_id = va_arg(ap, opus_int32); if (stream_id<0 || stream_id >= st->layout.nb_streams) - goto bad_arg; + ret = OPUS_BAD_ARG; value = va_arg(ap, OpusEncoder**); if (!value) { @@ -1284,6 +1313,7 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request, case OPUS_RESET_STATE: { int s; + st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0; if (st->mapping_type == MAPPING_TYPE_SURROUND) { OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels); @@ -1307,19 +1337,12 @@ int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request, 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; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; } void opus_multistream_encoder_destroy(OpusMSEncoder *st) diff --git a/thirdparty/opus/opus_private.h b/thirdparty/opus/opus_private.h index 5e2463f546..3b62eed096 100644 --- a/thirdparty/opus/opus_private.h +++ b/thirdparty/opus/opus_private.h @@ -33,7 +33,6 @@ #include "opus.h" #include "celt.h" -#include <stdarg.h> /* va_list */ #include <stddef.h> /* offsetof */ struct OpusRepacketizer { @@ -51,59 +50,12 @@ typedef struct ChannelLayout { 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 @@ -135,12 +87,19 @@ typedef void (*opus_copy_channel_out_func)( 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 compute_frame_size(const void *analysis_pcm, int frame_size, + int variable_duration, int C, opus_int32 Fs, int bitrate_bps, + int delay_compensation, downmix_func downmix +#ifndef DISABLE_FLOAT_API + , float *subframe_mem +#endif + ); + 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, @@ -172,30 +131,4 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int 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/thirdparty/opus/opus_projection_decoder.c b/thirdparty/opus/opus_projection_decoder.c deleted file mode 100644 index c2e07d5bcf..0000000000 --- a/thirdparty/opus/opus_projection_decoder.c +++ /dev/null @@ -1,258 +0,0 @@ -/* 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/thirdparty/opus/opus_projection_encoder.c b/thirdparty/opus/opus_projection_encoder.c deleted file mode 100644 index 06fb2d2526..0000000000 --- a/thirdparty/opus/opus_projection_encoder.c +++ /dev/null @@ -1,468 +0,0 @@ -/* 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/thirdparty/opus/opusfile.c b/thirdparty/opus/opusfile.c index 8b000a2c58..b8b3a354cf 100644 --- a/thirdparty/opus/opusfile.c +++ b/thirdparty/opus/opusfile.c @@ -86,15 +86,14 @@ int op_test(OpusHead *_head, 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); + data=ogg_sync_buffer(&oy,_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_sync_wrote(&oy,_initial_bytes); ogg_stream_init(&os,-1); err=OP_FALSE; do{ @@ -148,7 +147,7 @@ static int op_get_data(OggOpusFile *_of,int _nbytes){ int nbytes; OP_ASSERT(_nbytes>0); buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes); - nbytes=(int)(*_of->callbacks.read)(_of->stream,buffer,_nbytes); + nbytes=(int)(*_of->callbacks.read)(_of->source,buffer,_nbytes); OP_ASSERT(nbytes<=_nbytes); if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes); return nbytes; @@ -158,7 +157,7 @@ static int op_get_data(OggOpusFile *_of,int _nbytes){ 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)){ + ||(*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){ return OP_EREAD; } _of->offset=_offset; @@ -166,7 +165,7 @@ static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){ return 0; } -/*Get the current position indicator of the underlying stream. +/*Get the current position indicator of the underlying source. 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. @@ -370,7 +369,7 @@ static int op_get_prev_page_serial(OggOpusFile *_of,OpusSeekRecord *_sr, 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 + This should be impossible unless the contents of the source 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. @@ -456,7 +455,7 @@ static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp, } } /*We started from at or before the beginning of the link and found nothing. - This should be impossible unless the contents of the stream changed out + This should be impossible unless the contents of the source changed out from under us after we read from it.*/ if((OP_UNLIKELY(left_link)||OP_UNLIKELY(!begin))&&OP_UNLIKELY(_offset<0)){ return OP_EBADLINK; @@ -856,7 +855,6 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, /*Fail if the pre-skip is non-zero, since it's asking us to skip more samples than exist.*/ if(_link->head.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; @@ -868,8 +866,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, 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->pcm_end=_link->pcm_start=0; _link->end_offset=_link->data_offset; /*Tell the caller we've got a buffered page for them.*/ return 1; @@ -954,7 +951,6 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, /*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; @@ -1275,7 +1271,6 @@ static int op_bisect_forward_serialno(OggOpusFile *_of, 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; @@ -1395,8 +1390,8 @@ static int op_open_seekable2_impl(OggOpusFile *_of){ 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); + (*_of->callbacks.seek)(_of->source,0,SEEK_END); + _of->offset=_of->end=(*_of->callbacks.tell)(_of->source); if(OP_UNLIKELY(_of->end<0))return OP_EREAD; data_offset=_of->links[0].data_offset; if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK; @@ -1441,7 +1436,7 @@ static int op_open_seekable2(OggOpusFile *_of){ 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)); + OP_ASSERT((*_of->callbacks.tell)(_of->source)==op_position(_of)); ogg_sync_init(&_of->oy); ogg_stream_init(&_of->os,-1); ret=op_open_seekable2_impl(_of); @@ -1459,7 +1454,7 @@ static int op_open_seekable2(OggOpusFile *_of){ _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); + ret=(*_of->callbacks.seek)(_of->source,op_position(_of),SEEK_SET); return OP_UNLIKELY(ret<0)?OP_EREAD:0; } @@ -1498,20 +1493,19 @@ static void op_clear(OggOpusFile *_of){ _ogg_free(_of->serialnos); ogg_stream_clear(&_of->os); ogg_sync_clear(&_of->oy); - if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->stream); + if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->source); } static int op_open1(OggOpusFile *_of, - void *_stream,const OpusFileCallbacks *_cb, + void *_source,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->source=_source; *&_of->callbacks=*_cb; /*At a minimum, we need to be able to read data.*/ if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD; @@ -1526,18 +1520,18 @@ static int op_open1(OggOpusFile *_of, decoding entire files from RAM.*/ if(_initial_bytes>0){ char *buffer; - buffer=ogg_sync_buffer(&_of->oy,(long)_initial_bytes); + buffer=ogg_sync_buffer(&_of->oy,_initial_bytes); memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer)); - ogg_sync_wrote(&_of->oy,(long)_initial_bytes); + ogg_sync_wrote(&_of->oy,_initial_bytes); } /*Can we seek? Stevens suggests the seek test is portable.*/ - seekable=_cb->seek!=NULL&&(*_cb->seek)(_stream,0,SEEK_CUR)!=-1; + seekable=_cb->seek!=NULL&&(*_cb->seek)(_source,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); + pos=(*_of->callbacks.tell)(_of->source); /*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; @@ -1596,14 +1590,14 @@ static int op_open2(OggOpusFile *_of){ return ret; } -OggOpusFile *op_test_callbacks(void *_stream,const OpusFileCallbacks *_cb, +OggOpusFile *op_test_callbacks(void *_source,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); + ret=op_open1(of,_source,_cb,_initial_data,_initial_bytes); if(OP_LIKELY(ret>=0)){ if(_error!=NULL)*_error=0; return of; @@ -1617,10 +1611,10 @@ OggOpusFile *op_test_callbacks(void *_stream,const OpusFileCallbacks *_cb, return NULL; } -OggOpusFile *op_open_callbacks(void *_stream,const OpusFileCallbacks *_cb, +OggOpusFile *op_open_callbacks(void *_source,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); + of=op_test_callbacks(_source,_cb,_initial_data,_initial_bytes,_error); if(OP_LIKELY(of!=NULL)){ int ret; ret=op_open2(of); @@ -1633,15 +1627,15 @@ OggOpusFile *op_open_callbacks(void *_stream,const OpusFileCallbacks *_cb, /*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, +static OggOpusFile *op_open_close_on_failure(void *_source, const OpusFileCallbacks *_cb,int *_error){ OggOpusFile *of; - if(OP_UNLIKELY(_stream==NULL)){ + if(OP_UNLIKELY(_source==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); + of=op_open_callbacks(_source,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source); return of; } @@ -1659,15 +1653,15 @@ OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size, /*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, +static OggOpusFile *op_test_close_on_failure(void *_source, const OpusFileCallbacks *_cb,int *_error){ OggOpusFile *of; - if(OP_UNLIKELY(_stream==NULL)){ + if(OP_UNLIKELY(_source==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); + of=op_test_callbacks(_source,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source); return of; } @@ -1708,7 +1702,7 @@ int op_link_count(const OggOpusFile *_of){ return _of->nlinks; } -opus_uint32 op_serialno(const OggOpusFile *_of,int _li){ +ogg_uint32_t 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; @@ -1724,14 +1718,13 @@ opus_int64 op_raw_total(const OggOpusFile *_of,int _li){ ||OP_UNLIKELY(_li>=_of->nlinks)){ return OP_EINVAL; } - if(_li<0)return _of->end; + if(_li<0)return _of->end-_of->links[0].offset; return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset) - -(_li>0?_of->links[_li].offset:0); + -_of->links[_li].offset; } 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; @@ -1744,14 +1737,20 @@ ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){ /*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; + ogg_int64_t pcm_total; + int li; + pcm_total=0; + for(li=0;li<nlinks;li++){ + OP_ALWAYS_TRUE(!op_granpos_diff(&diff, + links[li].pcm_end,links[li].pcm_start)); + pcm_total+=diff-links[li].head.pre_skip; + } + return pcm_total; } OP_ALWAYS_TRUE(!op_granpos_diff(&diff, links[_li].pcm_end,links[_li].pcm_start)); - return pcm_total+diff-links[_li].head.pre_skip; + return diff-links[_li].head.pre_skip; } const OpusHead *op_head(const OggOpusFile *_of,int _li){ @@ -1821,34 +1820,6 @@ opus_int32 op_bitrate_instant(OggOpusFile *_of){ 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<nlinks&&_page_offset<links[_cur_link+1].offset? - _cur_link+1:nlinks; - do{ - if(_page_offset>=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. @@ -1905,28 +1876,19 @@ static int op_fetch_and_process_page(OggOpusFile *_of, if(OP_UNLIKELY(_of->ready_state<OP_STREAMSET)){ if(seekable){ ogg_uint32_t serialno; + int nlinks; + int li; serialno=ogg_page_serialno(&og); - /*Match the serialno to bitstream section.*/ - OP_ASSERT(cur_link>=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; - } - } + /*Match the serialno to bitstream section. + We use this rather than offset positions to avoid problems near + logical bitstream boundaries.*/ + nlinks=_of->nlinks; + for(li=0;li<nlinks&&links[li].serialno!=serialno;li++); + /*Not a desired Opus bitstream section. + Keep trying.*/ + if(li>=nlinks)continue; cur_serialno=serialno; - _of->cur_link=cur_link; + _of->cur_link=cur_link=li; 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 @@ -1980,32 +1942,13 @@ static int op_fetch_and_process_page(OggOpusFile *_of, 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.*/ + /*Drain the packets from the page anyway.*/ 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; - } + /*Report holes to the caller.*/ + if(!_ignore_holes)return OP_HOLE; } op_count=_of->op_count; /*If we found at least one audio data packet, compute per-packet granule @@ -2032,7 +1975,6 @@ static int op_fetch_and_process_page(OggOpusFile *_of, 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 @@ -2078,11 +2020,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of, &&OP_LIKELY(diff<total_duration)){ cur_packet_gp=prev_packet_gp; for(pi=0;pi<op_count;pi++){ - /*Check for overflow.*/ - if(diff<0&&OP_UNLIKELY(OP_INT64_MAX+diff<durations[pi])){ - diff=durations[pi]+1; - } - else diff=durations[pi]-diff; + diff=durations[pi]-diff; /*If we have samples to trim...*/ if(diff>0){ /*If we trimmed the entire packet, stop (the spec says encoders @@ -2138,11 +2076,10 @@ static int op_fetch_and_process_page(OggOpusFile *_of, } _of->prev_packet_gp=prev_packet_gp; _of->prev_page_offset=_page_offset; - _of->op_count=op_count=pi; + _of->op_count=pi; + /*If end-trimming didn't trim all the packets, we're done.*/ + if(OP_LIKELY(pi>0))return 0; } - if(report_hole)return OP_HOLE; - /*If end-trimming didn't trim all the packets, we're done.*/ - if(op_count>0)return 0; } } } @@ -2180,41 +2117,35 @@ 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; + int li; 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; + for(li=0;OP_LIKELY(li<nlinks);li++){ + ogg_int64_t pcm_start; + opus_int32 pre_skip; + pcm_start=links[li].pcm_start; + pre_skip=links[li].head.pre_skip; + OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li].pcm_end,pcm_start)); + duration-=pre_skip; + if(_pcm_offset<duration){ + _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; + return pcm_start; + } + _pcm_offset-=duration; + } + return -1; } /*A small helper to determine if an Ogg page contains data that continues onto @@ -2601,14 +2532,15 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){ ogg_int64_t gp; gp=_of->prev_packet_gp; if(OP_LIKELY(gp!=-1)){ - ogg_int64_t discard_count; - int nbuffered; + 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))){ + if(OP_LIKELY(!op_granpos_diff(&diff,gp,pcm_start))){ + ogg_int64_t discard_count; + discard_count=_pcm_offset-diff; /*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.*/ @@ -2674,14 +2606,22 @@ 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; + ogg_int64_t delta; + int li; links=_of->links; - OP_ASSERT(_li>=0&&_li<_of->nlinks); - pcm_offset=links[_li].pcm_file_offset; + pcm_offset=0; + OP_ASSERT(_li<_of->nlinks); + for(li=0;li<_li;li++){ + OP_ALWAYS_TRUE(!op_granpos_diff(&delta, + links[li].pcm_end,links[li].pcm_start)); + delta-=links[li].head.pre_skip; + pcm_offset+=delta; + } + OP_ASSERT(_li>=0); 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.*/ diff --git a/thirdparty/opus/repacketizer.c b/thirdparty/opus/repacketizer.c index bda44a148a..c80ee7f001 100644 --- a/thirdparty/opus/repacketizer.c +++ b/thirdparty/opus/repacketizer.c @@ -213,8 +213,7 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int { /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place padding from opus_packet_pad or opus_packet_unpad(). */ - /* assert disabled because it's not valid in C. */ - /* celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]); */ + celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]); OPUS_MOVE(ptr, frames[i], len[i]); ptr += len[i]; } diff --git a/thirdparty/opus/silk/A2NLSF.c b/thirdparty/opus/silk/A2NLSF.c index b487686ff9..b6e9e5ffcc 100644 --- a/thirdparty/opus/silk/A2NLSF.c +++ b/thirdparty/opus/silk/A2NLSF.c @@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. /* 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 +#define MAX_ITERATIONS_A2NLSF_FIX 30 /* Helper function for A2NLSF(..) */ /* Transforms polynomials from cos(n*f) to cos(f)^n */ @@ -130,7 +130,7 @@ void silk_A2NLSF( const opus_int d /* I Filter order (must be even) */ ) { - opus_int i, k, m, dd, root_ix, ffrac; + opus_int i, k, m, dd, root_ix, ffrac; opus_int32 xlo, xhi, xmid; opus_int32 ylo, yhi, ymid, thr; opus_int32 nom, den; @@ -239,13 +239,13 @@ void silk_A2NLSF( /* 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 ] ); + NLSF[ k ] = (opus_int16)silk_SMULBB( 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_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/ silk_A2NLSF_init( a_Q16, P, Q, dd ); p = P; /* Pointer to polynomial */ diff --git a/thirdparty/opus/silk/API.h b/thirdparty/opus/silk/API.h index 4d90ff9aa3..0131acbb08 100644 --- a/thirdparty/opus/silk/API.h +++ b/thirdparty/opus/silk/API.h @@ -80,8 +80,7 @@ opus_int silk_Encode( /* O Returns error co 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 */ + const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ ); /****************************************/ diff --git a/thirdparty/opus/silk/CNG.c b/thirdparty/opus/silk/CNG.c index ef8e38df9f..8443ad63bb 100644 --- a/thirdparty/opus/silk/CNG.c +++ b/thirdparty/opus/silk/CNG.c @@ -138,16 +138,16 @@ void silk_CNG( 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 ); + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); /* 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++ ) { + silk_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, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); @@ -170,11 +170,11 @@ void silk_CNG( } /* 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 ) ); - + CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q14[ MAX_LPC_ORDER + i ], 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 { diff --git a/thirdparty/opus/silk/LPC_analysis_filter.c b/thirdparty/opus/silk/LPC_analysis_filter.c index d34b5eb709..20906673ff 100644 --- a/thirdparty/opus/silk/LPC_analysis_filter.c +++ b/thirdparty/opus/silk/LPC_analysis_filter.c @@ -39,13 +39,6 @@ POSSIBILITY OF SUCH DAMAGE. /* 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 */ @@ -56,7 +49,8 @@ void silk_LPC_analysis_filter( ) { opus_int j; -#if defined(FIXED_POINT) && USE_CELT_FIR +#ifdef FIXED_POINT + opus_int16 mem[SILK_MAX_ORDER_LPC]; opus_int16 num[SILK_MAX_ORDER_LPC]; #else int ix; @@ -64,16 +58,19 @@ void silk_LPC_analysis_filter( const opus_int16 *in_ptr; #endif - celt_assert( d >= 6 ); - celt_assert( (d & 1) == 0 ); - celt_assert( d <= len ); + silk_assert( d >= 6 ); + silk_assert( (d & 1) == 0 ); + silk_assert( d <= len ); -#if defined(FIXED_POINT) && USE_CELT_FIR - celt_assert( d <= SILK_MAX_ORDER_LPC ); +#ifdef FIXED_POINT + silk_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++) { + mem[ j ] = in[ d - j - 1 ]; + } + celt_fir( in + d, num, out + d, len - d, d, mem, arch ); for ( j = 0; j < d; j++ ) { out[ j ] = 0; } diff --git a/thirdparty/opus/silk/LPC_fit.c b/thirdparty/opus/silk/LPC_fit.c deleted file mode 100644 index cdea4f3abc..0000000000 --- a/thirdparty/opus/silk/LPC_fit.c +++ /dev/null @@ -1,81 +0,0 @@ -/*********************************************************************** -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/thirdparty/opus/silk/LPC_inv_pred_gain.c b/thirdparty/opus/silk/LPC_inv_pred_gain.c index a3746a6ef9..4af89aa5fa 100644 --- a/thirdparty/opus/silk/LPC_inv_pred_gain.c +++ b/thirdparty/opus/silk/LPC_inv_pred_gain.c @@ -30,7 +30,6 @@ POSSIBILITY OF SUCH DAMAGE. #endif #include "SigProc_FIX.h" -#include "define.h" #define QA 24 #define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) @@ -39,103 +38,117 @@ POSSIBILITY OF SUCH DAMAGE. /* 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 */ +static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ 2 ][ 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 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA; + opus_int32 *Aold_QA, *Anew_QA; - invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + Anew_QA = A_QA[ order & 1 ]; + + invGain_Q30 = (opus_int32)1 << 30; for( k = order - 1; k > 0; k-- ) { /* Check for stability */ - if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) { return 0; } /* Set RC equal to negated AR coef */ - rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + rc_Q31 = -silk_LSHIFT( Anew_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 ) ); + rc_mult1_Q30 = ( (opus_int32)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 ) ); + /* 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 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 ); + /* Swap pointers */ + Aold_QA = Anew_QA; + Anew_QA = A_QA[ k & 1 ]; /* 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; + 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 ); } } /* Check for stability */ - if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) { return 0; } /* Set RC equal to negated AR coef */ - rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA ); /* Range: [ 1 : 2^30 ] */ - rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + rc_mult1_Q30 = ( (opus_int32)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; - } + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= 1<<30 ); 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 */ +opus_int32 silk_LPC_inverse_pred_gain( /* 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 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ]; + opus_int32 *Anew_QA; opus_int32 DC_resp = 0; + Anew_QA = Atmp_QA[ order & 1 ]; + /* 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 ); + Anew_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 ); + return LPC_inverse_pred_gain_QA( Atmp_QA, order ); } + +#ifdef FIXED_POINT + +/* For input in Q24 domain */ +opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int32 *A_Q24, /* I Prediction coefficients [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ]; + opus_int32 *Anew_QA; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA ); + } + + return LPC_inverse_pred_gain_QA( Atmp_QA, order ); +} +#endif diff --git a/thirdparty/opus/silk/LP_variable_cutoff.c b/thirdparty/opus/silk/LP_variable_cutoff.c index 79112ad354..f639e1f899 100644 --- a/thirdparty/opus/silk/LP_variable_cutoff.c +++ b/thirdparty/opus/silk/LP_variable_cutoff.c @@ -130,6 +130,6 @@ void silk_LP_variable_cutoff( /* 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); + silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1); } } diff --git a/thirdparty/opus/silk/MacroCount.h b/thirdparty/opus/silk/MacroCount.h index 78100ffede..834817d058 100644 --- a/thirdparty/opus/silk/MacroCount.h +++ b/thirdparty/opus/silk/MacroCount.h @@ -319,6 +319,14 @@ static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ return(tmp); } +#undef silk_ADD_POS_SAT64 +static OPUS_INLINE opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){ + opus_int64 tmp; + ops_count += 1; + tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b))); + return(tmp); +} + #undef silk_LSHIFT8 static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ opus_int8 ret; @@ -691,7 +699,7 @@ return(ret); #undef silk_LIMIT_32 -static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +static OPUS_INLINE opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) { opus_int32 ret; ops_count += 6; diff --git a/thirdparty/opus/silk/MacroDebug.h b/thirdparty/opus/silk/MacroDebug.h index 8dd4ce2ee2..35aedc5c5f 100644 --- a/thirdparty/opus/silk/MacroDebug.h +++ b/thirdparty/opus/silk/MacroDebug.h @@ -539,7 +539,8 @@ static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, cha 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 */ + no checking needed for silk_ADD_POS_SAT32 + no checking needed for silk_ADD_POS_SAT64 */ #undef silk_LSHIFT8 #define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__) diff --git a/thirdparty/opus/silk/NLSF2A.c b/thirdparty/opus/silk/NLSF2A.c index d5b7730638..b1c559ea68 100644 --- a/thirdparty/opus/silk/NLSF2A.c +++ b/thirdparty/opus/silk/NLSF2A.c @@ -66,8 +66,7 @@ static OPUS_INLINE void silk_NLSF2A_find_poly( 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 */ + const opus_int d /* I filter order (should be even) */ ) { /* This ordering was found to maximize quality. It improves numerical accuracy of @@ -84,14 +83,15 @@ void silk_NLSF2A( 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 ]; + opus_int32 maxabs, absval, idx=0, sc_Q16; silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); - celt_assert( d==10 || d==16 ); + silk_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 ); + silk_assert(NLSF[k] >= 0 ); /* f_int on a scale 0-127 (rounded down) */ f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); @@ -126,15 +126,52 @@ void silk_NLSF2A( 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 ); + /* 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( a32_QA1[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */ + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + sc_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( a32_QA1, d, sc_Q16 ); + } else { + break; + } + } - 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 ) ); + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ for( k = 0; k < d; k++ ) { - a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */ + a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 ); + } + } else { + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } + + for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + /* 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 */ + } + } else { + break; } } } diff --git a/thirdparty/opus/silk/NLSF_VQ.c b/thirdparty/opus/silk/NLSF_VQ.c index b83182a79c..69b6e22e18 100644 --- a/thirdparty/opus/silk/NLSF_VQ.c +++ b/thirdparty/opus/silk/NLSF_VQ.c @@ -33,44 +33,36 @@ POSSIBILITY OF SUCH DAMAGE. /* 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] */ + 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 */ ) { - 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; + opus_int i, m; + opus_int32 diff_Q15, sum_error_Q30, sum_error_Q26; - celt_assert( ( LPC_order & 1 ) == 0 ); + silk_assert( LPC_order <= 16 ); + silk_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; + sum_error_Q26 = 0; + for( m = 0; m < LPC_order; m += 2 ) { + /* Compute weighted squared quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/ + sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 ); - /* 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; + /* Compute weighted squared quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/ + sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 ); - silk_assert( sum_error_Q24 >= 0 ); + sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 ); + + silk_assert( sum_error_Q26 >= 0 ); + silk_assert( sum_error_Q30 >= 0 ); } - err_Q24[ i ] = sum_error_Q24; - cb_Q8_ptr += LPC_order; - w_Q9_ptr += LPC_order; + err_Q26[ i ] = sum_error_Q26; } } diff --git a/thirdparty/opus/silk/NLSF_VQ_weights_laroia.c b/thirdparty/opus/silk/NLSF_VQ_weights_laroia.c index 9873bcde10..04894c59ab 100644 --- a/thirdparty/opus/silk/NLSF_VQ_weights_laroia.c +++ b/thirdparty/opus/silk/NLSF_VQ_weights_laroia.c @@ -48,8 +48,8 @@ void silk_NLSF_VQ_weights_laroia( opus_int k; opus_int32 tmp1_int, tmp2_int; - celt_assert( D > 0 ); - celt_assert( ( D & 1 ) == 0 ); + silk_assert( D > 0 ); + silk_assert( ( D & 1 ) == 0 ); /* First value */ tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); diff --git a/thirdparty/opus/silk/NLSF_decode.c b/thirdparty/opus/silk/NLSF_decode.c index eeb0ba8c92..9f715060b8 100644 --- a/thirdparty/opus/silk/NLSF_decode.c +++ b/thirdparty/opus/silk/NLSF_decode.c @@ -32,7 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "main.h" /* Predictive dequantizer for NLSF residuals */ -static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ +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 ] */ @@ -70,9 +70,15 @@ void silk_NLSF_decode( 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; + opus_int16 W_tmp_QW[ MAX_LPC_ORDER ]; + opus_int32 W_tmp_Q9, NLSF_Q15_tmp; const opus_uint8 *pCB_element; - const opus_int16 *pCB_Wght_Q9; + + /* Decode first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 ); + } /* Unpack entropy table indices and predictor for current CB1 index */ silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); @@ -80,11 +86,13 @@ void silk_NLSF_decode( /* 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 ]; + /* Weights from codebook vector */ + silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights and add to output */ 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 ); + W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) ); + NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) ); pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); } diff --git a/thirdparty/opus/silk/NLSF_del_dec_quant.c b/thirdparty/opus/silk/NLSF_del_dec_quant.c index 44a16acd0b..de88fee060 100644 --- a/thirdparty/opus/silk/NLSF_del_dec_quant.c +++ b/thirdparty/opus/silk/NLSF_del_dec_quant.c @@ -84,7 +84,7 @@ opus_int32 silk_NLSF_del_dec_quant( /* O Returns nStates = 1; RD_Q25[ 0 ] = 0; prev_out_Q10[ 0 ] = 0; - for( i = order - 1; i >= 0; i-- ) { + for( i = order - 1; ; i-- ) { rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; in_Q10 = x_Q10[ i ]; for( j = 0; j < nStates; j++ ) { @@ -131,7 +131,7 @@ opus_int32 silk_NLSF_del_dec_quant( /* O Returns 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 ) { + if( nStates <= ( NLSF_QUANT_DEL_DEC_STATES >> 1 ) ) { /* double number of states and copy */ for( j = 0; j < nStates; j++ ) { ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; @@ -140,7 +140,7 @@ opus_int32 silk_NLSF_del_dec_quant( /* O Returns for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { ind[ j ][ i ] = ind[ j - nStates ][ i ]; } - } else { + } else if( i > 0 ) { /* 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 ] ) { @@ -191,6 +191,8 @@ opus_int32 silk_NLSF_del_dec_quant( /* O Returns for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); } + } else { /* i == 0 */ + break; } } diff --git a/thirdparty/opus/silk/NLSF_encode.c b/thirdparty/opus/silk/NLSF_encode.c index 01ac7db78c..f03c3f1c35 100644 --- a/thirdparty/opus/silk/NLSF_encode.c +++ b/thirdparty/opus/silk/NLSF_encode.c @@ -37,9 +37,9 @@ POSSIBILITY OF SUCH DAMAGE. /***********************/ 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 ] */ + 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_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ + 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 */ @@ -47,32 +47,34 @@ opus_int32 silk_NLSF_encode( /* O Returns { opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; opus_int32 W_tmp_Q9, ret; - VARDECL( opus_int32, err_Q24 ); + VARDECL( opus_int32, err_Q26 ); VARDECL( opus_int32, RD_Q25 ); VARDECL( opus_int, tempIndices1 ); VARDECL( opus_int8, tempIndices2 ); + opus_int16 res_Q15[ MAX_LPC_ORDER ]; opus_int16 res_Q10[ MAX_LPC_ORDER ]; opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_tmp_QW[ 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( nSurvivors <= NLSF_VQ_MAX_SURVIVORS ); + silk_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 ); + ALLOC( err_Q26, psNLSF_CB->nVectors, opus_int32 ); + silk_NLSF_VQ( err_Q26, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, 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 ); + silk_insertion_sort_increasing( err_Q26, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); ALLOC( RD_Q25, nSurvivors, opus_int32 ); ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 ); @@ -83,12 +85,23 @@ opus_int32 silk_NLSF_encode( /* O Returns /* 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 ); + res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ]; + } + + /* Weights from codebook vector */ + silk_NLSF_VQ_weights_laroia( W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB->order ); + + /* Apply square-rooted weights */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) ); + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 ); + } + + /* Modify input weights accordingly */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] ); } /* Unpack entropy table indices and predictor for current CB1 index */ diff --git a/thirdparty/opus/silk/NSQ.c b/thirdparty/opus/silk/NSQ.c index 1d64d8e257..43e3fee7e0 100644 --- a/thirdparty/opus/silk/NSQ.c +++ b/thirdparty/opus/silk/NSQ.c @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. 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 */ + 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 */ @@ -75,14 +75,14 @@ static OPUS_INLINE void silk_noise_shape_quantizer( void silk_NSQ_c ( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O Encoder State */ silk_nsq_state *NSQ, /* I/O NSQ state */ SideInfoIndices *psIndices, /* I/O Quantization Indices */ - const opus_int16 x16[], /* I Input */ + 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 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping 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 */ @@ -117,7 +117,8 @@ void silk_NSQ_c LSF_interpolation_flag = 1; } - ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + 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 */ @@ -127,7 +128,7 @@ void silk_NSQ_c 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 ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; /* Noise shape parameters */ silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); @@ -143,7 +144,7 @@ void silk_NSQ_c 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_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 ); @@ -153,13 +154,13 @@ void silk_NSQ_c } } - silk_nsq_scale_states( psEncC, NSQ, x16, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + silk_nsq_scale_states( psEncC, NSQ, x_Q3, 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; + x_Q3 += psEncC->subfr_length; pulses += psEncC->subfr_length; pxq += psEncC->subfr_length; } @@ -168,6 +169,7 @@ void silk_NSQ_c NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; /* Save quantized speech and noise shaping signals */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */ 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; @@ -247,15 +249,15 @@ void silk_noise_shape_quantizer( } /* 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); + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(psLPC_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 ); + 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 */ @@ -277,27 +279,14 @@ void silk_noise_shape_quantizer( 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; + 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 ); @@ -348,8 +337,7 @@ void silk_noise_shape_quantizer( /* 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 ); + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_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 ); @@ -368,7 +356,7 @@ void silk_noise_shape_quantizer( 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 */ + 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 */ @@ -380,18 +368,28 @@ static OPUS_INLINE void silk_nsq_scale_states( ) { opus_int i, lag; - opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; 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_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); for( i = 0; i < psEncC->subfr_length; i++ ) { - x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + 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 ) { @@ -405,9 +403,7 @@ static OPUS_INLINE void silk_nsq_scale_states( } /* 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 ); - + if( gain_adj_Q16 != (opus_int32)1 << 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 ] ); @@ -421,7 +417,6 @@ static OPUS_INLINE void silk_nsq_scale_states( } 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++ ) { @@ -430,8 +425,5 @@ static OPUS_INLINE void silk_nsq_scale_states( 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/thirdparty/opus/silk/NSQ_del_dec.c b/thirdparty/opus/silk/NSQ_del_dec.c index 3fd9fa0d5b..ab6feeac98 100644 --- a/thirdparty/opus/silk/NSQ_del_dec.c +++ b/thirdparty/opus/silk/NSQ_del_dec.c @@ -43,7 +43,6 @@ typedef struct { 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; @@ -54,7 +53,6 @@ typedef struct { 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; @@ -68,7 +66,7 @@ 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 */ + 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 */ @@ -109,20 +107,20 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( 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 *smpl_buf_idx, /* I 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 */ + const silk_encoder_state *psEncC, /* I/O Encoder State */ silk_nsq_state *NSQ, /* I/O NSQ state */ SideInfoIndices *psIndices, /* I/O Quantization Indices */ - const opus_int16 x16[], /* I Input */ + 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 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping 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 */ @@ -161,7 +159,6 @@ void silk_NSQ_del_dec_c( 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 ) ); @@ -189,7 +186,8 @@ void silk_NSQ_del_dec_c( LSF_interpolation_flag = 1; } - ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + 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 ); @@ -201,7 +199,7 @@ void silk_NSQ_del_dec_c( 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 ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; /* Noise shape parameters */ silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); @@ -237,8 +235,7 @@ void silk_NSQ_del_dec_c( 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; + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; 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 ) ); @@ -250,7 +247,7 @@ void silk_NSQ_del_dec_c( /* Rewhiten with new A coefs */ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; - celt_assert( start_idx > 0 ); + 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 ); @@ -260,7 +257,7 @@ void silk_NSQ_del_dec_c( } } - silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + silk_nsq_del_dec_scale_states( 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( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, @@ -268,7 +265,7 @@ void silk_NSQ_del_dec_c( 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; + x_Q3 += psEncC->subfr_length; pulses += psEncC->subfr_length; pxq += psEncC->subfr_length; } @@ -289,9 +286,7 @@ void silk_NSQ_del_dec_c( 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; - + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; 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 ) ); @@ -302,10 +297,10 @@ void silk_NSQ_del_dec_c( /* 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 */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */ 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; @@ -340,7 +335,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( 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 *smpl_buf_idx, /* I Index to newest samples in buffers */ opus_int decisionDelay, /* I */ int arch /* I */ ) @@ -361,7 +356,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( NSQ_sample_struct *psSS; SAVE_STACK; - celt_assert( nStatesDelayedDecision > 0 ); + silk_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 ]; @@ -419,9 +414,9 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ /* Noise shape feedback */ - celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + silk_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 ); + 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; @@ -467,19 +462,6 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( /* 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 ); @@ -533,8 +515,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( 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 ); + 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; @@ -548,22 +529,21 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( 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 ); + 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; + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */ + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */ /* Find winner */ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; @@ -627,7 +607,6 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( 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; @@ -652,7 +631,7 @@ 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 */ + 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 */ @@ -666,19 +645,29 @@ static OPUS_INLINE void silk_nsq_del_dec_scale_states( ) { opus_int i, k, lag; - opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; 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 ); + /* 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_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); for( i = 0; i < psEncC->subfr_length; i++ ) { - x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + 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 ) { @@ -692,9 +681,7 @@ static OPUS_INLINE void silk_nsq_del_dec_scale_states( } /* 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 ); - + if( gain_adj_Q16 != (opus_int32)1 << 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 ] ); @@ -712,7 +699,6 @@ static OPUS_INLINE void silk_nsq_del_dec_scale_states( /* 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++ ) { @@ -726,8 +712,5 @@ static OPUS_INLINE void silk_nsq_del_dec_scale_states( 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/thirdparty/opus/silk/PLC.c b/thirdparty/opus/silk/PLC.c index f89391651c..fb6ea887b7 100644 --- a/thirdparty/opus/silk/PLC.c +++ b/thirdparty/opus/silk/PLC.c @@ -275,7 +275,7 @@ static OPUS_INLINE void silk_PLC_conceal( /* 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 ); + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order ); 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 ); @@ -291,7 +291,7 @@ static OPUS_INLINE void silk_PLC_conceal( /* Rewhiten LTP state */ idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; - celt_assert( idx > 0 ); + silk_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 ); @@ -328,10 +328,8 @@ static OPUS_INLINE void silk_PLC_conceal( 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 ); - } + /* 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 ); @@ -347,7 +345,7 @@ static OPUS_INLINE void silk_PLC_conceal( /* 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 */ + silk_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 */ diff --git a/thirdparty/opus/silk/SigProc_FIX.h b/thirdparty/opus/silk/SigProc_FIX.h index f9ae326326..b63299441e 100644 --- a/thirdparty/opus/silk/SigProc_FIX.h +++ b/thirdparty/opus/silk/SigProc_FIX.h @@ -35,7 +35,7 @@ extern "C" /*#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() */ +#define SILK_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */ #include <string.h> /* for memset(), memcpy(), memmove() */ #include "typedef.h" @@ -47,11 +47,6 @@ extern "C" #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 */ /********************************************************************/ @@ -101,22 +96,14 @@ void silk_resampler_down2_3( * slower than biquad() but uses more precise coefficients * can handle (slowly) varying coefficients */ -void silk_biquad_alt_stride1( +void silk_biquad_alt( 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) */ + const opus_int32 len, /* I signal length (must be even) */ + opus_int stride /* I Operate on interleaved signal if > 1 */ ); /* Variable order MA prediction error filter. */ @@ -145,11 +132,17 @@ void silk_bwexpander_32( /* 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 */ +opus_int32 silk_LPC_inverse_pred_gain( /* 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 */ ); +/* For input in Q24 domain */ +opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int32 *A_Q24, /* I Prediction coefficients [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] */ @@ -159,14 +152,6 @@ void silk_ana_filt_bank_1( 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 */ /********************************************************************/ @@ -286,17 +271,7 @@ void silk_A2NLSF( 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 */ + const opus_int d /* I filter order (should be even) */ ); void silk_insertion_sort_increasing( @@ -496,7 +471,8 @@ static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) /* 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_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT64(a, b) ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_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 */ @@ -596,9 +572,7 @@ static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) /* 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))) +#define silk_RAND(seed) (silk_MLA_ovflw(907633515, (seed), 196314165)) /* Add some multiplication functions that can be easily mapped to ARM. */ diff --git a/thirdparty/opus/silk/VAD.c b/thirdparty/opus/silk/VAD.c index d0cda52162..0a782af2f1 100644 --- a/thirdparty/opus/silk/VAD.c +++ b/thirdparty/opus/silk/VAD.c @@ -101,9 +101,9 @@ opus_int silk_VAD_GetSA_Q8_c( /* O Return v /* 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 ) ); + silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + silk_assert( psEncC->frame_length <= 512 ); + silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); /***********************/ /* Filter and Decimate */ @@ -252,14 +252,15 @@ opus_int silk_VAD_GetSA_Q8_c( /* O Return v 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 ); + } 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 ); @@ -312,8 +313,6 @@ void silk_VAD_GetNoiseLevels( /* 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; } @@ -357,4 +356,7 @@ void silk_VAD_GetNoiseLevels( /* Store as part of state */ psSilk_VAD->NL[ k ] = nl; } + + /* Increment frame counter */ + psSilk_VAD->counter++; } diff --git a/thirdparty/opus/silk/VQ_WMat_EC.c b/thirdparty/opus/silk/VQ_WMat_EC.c index 0f3d545c4e..7983f1db80 100644 --- a/thirdparty/opus/silk/VQ_WMat_EC.c +++ b/thirdparty/opus/silk/VQ_WMat_EC.c @@ -34,95 +34,84 @@ POSSIBILITY OF SUCH DAMAGE. /* 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_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ 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_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 subfr_len, /* I number of samples per subframe */ + 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 */ - const opus_int L /* I number of vectors in codebook */ + 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 ); + opus_int16 diff_Q14[ 5 ]; + opus_int32 sum1_Q14, sum2_Q16; /* Loop over codebook */ - *rate_dist_Q8 = silk_int32_MAX; - *res_nrg_Q15 = silk_int32_MAX; + *rate_dist_Q14 = 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]; + + diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); + diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 ); + diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 ); + diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 ); + diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 ); + /* Weighted rate */ - /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */ - sum1_Q15 = SILK_FIX_CONST( 1.001, 15 ); + sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); /* 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 ] ); + 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 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + 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_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; - } + 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 */ diff --git a/thirdparty/opus/silk/arm/LPC_inv_pred_gain_arm.h b/thirdparty/opus/silk/arm/LPC_inv_pred_gain_arm.h deleted file mode 100644 index 9895b555c8..0000000000 --- a/thirdparty/opus/silk/arm/LPC_inv_pred_gain_arm.h +++ /dev/null @@ -1,57 +0,0 @@ -/*********************************************************************** -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/thirdparty/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c b/thirdparty/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c deleted file mode 100644 index ab426bcd66..0000000000 --- a/thirdparty/opus/silk/arm/LPC_inv_pred_gain_neon_intr.c +++ /dev/null @@ -1,280 +0,0 @@ -/*********************************************************************** -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 <arm_neon.h> -#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/thirdparty/opus/silk/arm/NSQ_del_dec_arm.h b/thirdparty/opus/silk/arm/NSQ_del_dec_arm.h deleted file mode 100644 index 9e76e16927..0000000000 --- a/thirdparty/opus/silk/arm/NSQ_del_dec_arm.h +++ /dev/null @@ -1,100 +0,0 @@ -/*********************************************************************** -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/thirdparty/opus/silk/arm/NSQ_del_dec_neon_intr.c b/thirdparty/opus/silk/arm/NSQ_del_dec_neon_intr.c deleted file mode 100644 index 212410f362..0000000000 --- a/thirdparty/opus/silk/arm/NSQ_del_dec_neon_intr.c +++ /dev/null @@ -1,1124 +0,0 @@ -/*********************************************************************** -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 <arm_neon.h> -#ifdef OPUS_CHECK_ASM -# include <string.h> -#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/thirdparty/opus/silk/arm/NSQ_neon.h b/thirdparty/opus/silk/arm/NSQ_neon.h index b31d9442d6..77c946af85 100644 --- a/thirdparty/opus/silk/arm/NSQ_neon.h +++ b/thirdparty/opus/silk/arm/NSQ_neon.h @@ -28,31 +28,30 @@ POSSIBILITY OF SUCH DAMAGE. #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); + out[15] = in[0] << 15; + out[14] = in[1] << 15; + out[13] = in[2] << 15; + out[12] = in[3] << 15; + out[11] = in[4] << 15; + out[10] = in[5] << 15; + out[9] = in[6] << 15; + out[8] = in[7] << 15; + out[7] = in[8] << 15; + out[6] = 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); + out[5] = in[10] << 15; + out[4] = in[11] << 15; + out[3] = in[12] << 15; + out[2] = in[13] << 15; + out[1] = in[14] << 15; + out[0] = in[15] << 15; } else { diff --git a/thirdparty/opus/silk/arm/arm_silk_map.c b/thirdparty/opus/silk/arm/arm_silk_map.c index 0b9bfec2ca..9bd86a7b21 100644 --- a/thirdparty/opus/silk/arm/arm_silk_map.c +++ b/thirdparty/opus/silk/arm/arm_silk_map.c @@ -28,62 +28,13 @@ POSSIBILITY OF SUCH DAMAGE. # 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. @@ -101,23 +52,4 @@ opus_int32 # 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/thirdparty/opus/silk/arm/biquad_alt_arm.h b/thirdparty/opus/silk/arm/biquad_alt_arm.h deleted file mode 100644 index 66ea9f43dd..0000000000 --- a/thirdparty/opus/silk/arm/biquad_alt_arm.h +++ /dev/null @@ -1,68 +0,0 @@ -/*********************************************************************** -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/thirdparty/opus/silk/arm/biquad_alt_neon_intr.c b/thirdparty/opus/silk/arm/biquad_alt_neon_intr.c deleted file mode 100644 index 9715733185..0000000000 --- a/thirdparty/opus/silk/arm/biquad_alt_neon_intr.c +++ /dev/null @@ -1,156 +0,0 @@ -/*********************************************************************** -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 <arm_neon.h> -#ifdef OPUS_CHECK_ASM -# include <string.h> -# 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/thirdparty/opus/silk/arm/macros_armv4.h b/thirdparty/opus/silk/arm/macros_armv4.h index 877eb18dd5..3f30e97288 100644 --- a/thirdparty/opus/silk/arm/macros_armv4.h +++ b/thirdparty/opus/silk/arm/macros_armv4.h @@ -28,11 +28,6 @@ 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) @@ -43,7 +38,7 @@ static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b) "#silk_SMULWB\n\t" "smull %0, %1, %2, %3\n\t" : "=&r"(rd_lo), "=&r"(rd_hi) - : "%r"(a), "r"(SAFE_SHL(b,16)) + : "%r"(a), "r"(b<<16) ); return rd_hi; } @@ -85,7 +80,7 @@ static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b) : "=&r"(rd_lo), "=&r"(rd_hi) : "%r"(a), "r"(b) ); - return SAFE_SHL(rd_hi,16)+(rd_lo>>16); + return (rd_hi<<16)+(rd_lo>>16); } #define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b)) @@ -101,10 +96,8 @@ static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b, : "=&r"(rd_lo), "=&r"(rd_hi) : "%r"(b), "r"(c) ); - return a+SAFE_SHL(rd_hi,16)+(rd_lo>>16); + return a+(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/thirdparty/opus/silk/arm/macros_armv5e.h b/thirdparty/opus/silk/arm/macros_armv5e.h index b14ec65ddb..aad4117e46 100644 --- a/thirdparty/opus/silk/arm/macros_armv5e.h +++ b/thirdparty/opus/silk/arm/macros_armv5e.h @@ -29,11 +29,6 @@ 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) @@ -195,7 +190,7 @@ static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16) "#silk_CLZ16\n\t" "clz %0, %1;\n" : "=r"(res) - : "r"(SAFE_SHL(in16,16)|0x8000) + : "r"(in16<<16|0x8000) ); return res; } @@ -215,6 +210,4 @@ static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32) } #define silk_CLZ32(in32) (silk_CLZ32_armv5(in32)) -#undef SAFE_SHL - #endif /* SILK_MACROS_ARMv5E_H */ diff --git a/thirdparty/opus/silk/biquad_alt.c b/thirdparty/opus/silk/biquad_alt.c index 54566a43c0..d55f5ee92e 100644 --- a/thirdparty/opus/silk/biquad_alt.c +++ b/thirdparty/opus/silk/biquad_alt.c @@ -39,13 +39,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "SigProc_FIX.h" /* Second order ARMA filter, alternative implementation */ -void silk_biquad_alt_stride1( +void silk_biquad_alt( 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) */ + const opus_int32 len, /* I signal length (must be even) */ + opus_int stride /* I Operate on interleaved signal if > 1 */ ) { /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ @@ -60,7 +61,7 @@ void silk_biquad_alt_stride1( for( k = 0; k < len; k++ ) { /* S[ 0 ], S[ 1 ]: Q12 */ - inval = in[ k ]; + inval = in[ k * stride ]; 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 ); @@ -72,50 +73,6 @@ void silk_biquad_alt_stride1( 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 ) ); + out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); } } diff --git a/thirdparty/opus/silk/bwexpander.c b/thirdparty/opus/silk/bwexpander.c index afa97907ec..2eb4456695 100644 --- a/thirdparty/opus/silk/bwexpander.c +++ b/thirdparty/opus/silk/bwexpander.c @@ -45,7 +45,7 @@ void silk_bwexpander( /* 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 ); + 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/thirdparty/opus/silk/check_control_input.c b/thirdparty/opus/silk/check_control_input.c index 739fb01f1e..b5de9ce48d 100644 --- a/thirdparty/opus/silk/check_control_input.c +++ b/thirdparty/opus/silk/check_control_input.c @@ -38,7 +38,7 @@ opus_int check_control_input( silk_EncControlStruct *encControl /* I Control structure */ ) { - celt_assert( encControl != NULL ); + silk_assert( encControl != NULL ); if( ( ( encControl->API_sampleRate != 8000 ) && ( encControl->API_sampleRate != 12000 ) && @@ -59,46 +59,46 @@ opus_int check_control_input( ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { - celt_assert( 0 ); + silk_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 ); + silk_assert( 0 ); return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; } if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_LOSS_RATE; } if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_DTX_SETTING; } if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_CBR_SETTING; } if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_INBAND_FEC_SETTING; } if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; } if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; } if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; } if( encControl->complexity < 0 || encControl->complexity > 10 ) { - celt_assert( 0 ); + silk_assert( 0 ); return SILK_ENC_INVALID_COMPLEXITY_SETTING; } diff --git a/thirdparty/opus/silk/control.h b/thirdparty/opus/silk/control.h index b76ec33cd6..747e5426a0 100644 --- a/thirdparty/opus/silk/control.h +++ b/thirdparty/opus/silk/control.h @@ -77,9 +77,6 @@ typedef struct { /* 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; @@ -113,11 +110,6 @@ typedef struct { /* 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; /**************************************************************************/ diff --git a/thirdparty/opus/silk/control_SNR.c b/thirdparty/opus/silk/control_SNR.c index 9a6db27543..cee87eb0d8 100644 --- a/thirdparty/opus/silk/control_SNR.c +++ b/thirdparty/opus/silk/control_SNR.c @@ -32,82 +32,45 @@ POSSIBILITY OF SUCH DAMAGE. #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; + opus_int k, ret = SILK_NO_ERROR; + opus_int32 frac_Q6; + const opus_int32 *rateTable; - 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; + /* Set bitrate/coding quality */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS ); + if( TargetRate_bps != psEncC->TargetRate_bps ) { + psEncC->TargetRate_bps = TargetRate_bps; + + /* If new TargetRate_bps, translate to SNR_dB value */ + if( psEncC->fs_kHz == 8 ) { + rateTable = silk_TargetRate_table_NB; + } else if( psEncC->fs_kHz == 12 ) { + rateTable = silk_TargetRate_table_MB; + } else { + rateTable = silk_TargetRate_table_WB; + } + + /* Reduce bitrate for 10 ms modes in these calculations */ + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= REDUCE_BITRATE_10_MS_BPS; + } + + /* Find bitrate interval in table and interpolate */ + for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) { + if( TargetRate_bps <= rateTable[ k ] ) { + frac_Q6 = silk_DIV32( silk_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ), + rateTable[ k ] - rateTable[ k - 1 ] ); + psEncC->SNR_dB_Q7 = silk_LSHIFT( silk_SNR_table_Q1[ k - 1 ], 6 ) + silk_MUL( frac_Q6, silk_SNR_table_Q1[ k ] - silk_SNR_table_Q1[ k - 1 ] ); + break; + } + } } - return SILK_NO_ERROR; + + return ret; } diff --git a/thirdparty/opus/silk/control_audio_bandwidth.c b/thirdparty/opus/silk/control_audio_bandwidth.c index f6d22d8395..4f9bc5cbda 100644 --- a/thirdparty/opus/silk/control_audio_bandwidth.c +++ b/thirdparty/opus/silk/control_audio_bandwidth.c @@ -39,15 +39,9 @@ opus_int silk_control_audio_bandwidth( ) { 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_kHz = psEncC->fs_kHz; fs_Hz = silk_SMULBB( fs_kHz, 1000 ); if( fs_Hz == 0 ) { /* Encoder has just been initialized */ @@ -67,7 +61,7 @@ opus_int silk_control_audio_bandwidth( } if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { /* Check if we should switch down */ - if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + if( silk_SMULBB( psEncC->fs_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) { /* Switch down */ if( psEncC->sLP.mode == 0 ) { @@ -82,7 +76,7 @@ opus_int silk_control_audio_bandwidth( psEncC->sLP.mode = 0; /* Switch to a lower sample frequency */ - fs_kHz = orig_kHz == 16 ? 12 : 8; + fs_kHz = psEncC->fs_kHz == 16 ? 12 : 8; } else { if( psEncC->sLP.transition_frame_no <= 0 ) { encControl->switchReady = 1; @@ -96,12 +90,12 @@ opus_int silk_control_audio_bandwidth( } else /* Check if we should switch up */ - if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + if( silk_SMULBB( psEncC->fs_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) { /* Switch up */ if( encControl->opusCanSwitch ) { /* Switch to a higher sample frequency */ - fs_kHz = orig_kHz == 8 ? 12 : 16; + fs_kHz = psEncC->fs_kHz == 8 ? 12 : 16; /* New transition */ psEncC->sLP.transition_frame_no = 0; diff --git a/thirdparty/opus/silk/control_codec.c b/thirdparty/opus/silk/control_codec.c index 52aa8fded3..044eea3f2a 100644 --- a/thirdparty/opus/silk/control_codec.c +++ b/thirdparty/opus/silk/control_codec.c @@ -57,7 +57,7 @@ static opus_int silk_setup_complexity( static OPUS_INLINE opus_int silk_setup_LBRR( silk_encoder_state *psEncC, /* I/O */ - const silk_EncControlStruct *encControl /* I */ + const opus_int32 TargetRate_bps /* I */ ); @@ -65,6 +65,7 @@ static OPUS_INLINE opus_int silk_setup_LBRR( 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_int32 TargetRate_bps, /* I Target max bitrate (bps) */ 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 @@ -124,7 +125,7 @@ opus_int silk_control_encoder( /********************************************/ /* Set LBRR usage */ /********************************************/ - ret += silk_setup_LBRR( &psEnc->sCmn, encControl ); + ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps ); psEnc->sCmn.controlled_since_last_payload = 1; @@ -238,11 +239,12 @@ static opus_int silk_setup_fs( } /* 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 ); + silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + silk_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->sPrefilt, 0, sizeof( psEnc->sPrefilt ) ); 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 ) ); @@ -253,6 +255,7 @@ static opus_int silk_setup_fs( /* Initialize non-zero parameters */ psEnc->sCmn.prevLag = 100; psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sPrefilt.lagPrev = 100; psEnc->sShape.LastGainIndex = 10; psEnc->sCmn.sNSQ.lagPrev = 100; psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; @@ -290,16 +293,19 @@ static opus_int silk_setup_fs( 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.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_WB, 9 ); psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_MB, 9 ); psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; } else { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_NB, 9 ); 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 ); + silk_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); return ret; } @@ -312,76 +318,61 @@ static opus_int silk_setup_complexity( opus_int ret = 0; /* Set encoding complexity */ - celt_assert( Complexity >= 0 && Complexity <= 10 ); - if( Complexity < 1 ) { + silk_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 2 ) { psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); psEncC->pitchEstimationLPCOrder = 6; - psEncC->shapingLPCOrder = 12; + psEncC->shapingLPCOrder = 8; 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->LTPQuantLowComplexity = 1; 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->shapingLPCOrder = 10; psEncC->la_shape = 5 * psEncC->fs_kHz; - psEncC->nStatesDelayedDecision = 2; + psEncC->nStatesDelayedDecision = 1; psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 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->shapingLPCOrder = 12; psEncC->la_shape = 5 * psEncC->fs_kHz; psEncC->nStatesDelayedDecision = 2; psEncC->useInterpolatedNLSFs = 1; - psEncC->NLSF_MSVQ_Survivors = 6; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 8; 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->shapingLPCOrder = 14; psEncC->la_shape = 5 * psEncC->fs_kHz; psEncC->nStatesDelayedDecision = 3; psEncC->useInterpolatedNLSFs = 1; - psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 16; 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->shapingLPCOrder = 16; psEncC->la_shape = 5 * psEncC->fs_kHz; psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; psEncC->useInterpolatedNLSFs = 1; - psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 32; psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); } @@ -390,32 +381,46 @@ static opus_int silk_setup_complexity( 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 ); + silk_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + silk_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + silk_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + silk_assert( psEncC->warping_Q16 <= 32767 ); + silk_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + silk_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + silk_assert( psEncC->NLSF_MSVQ_Survivors <= NLSF_VQ_MAX_SURVIVORS ); return ret; } static OPUS_INLINE opus_int silk_setup_LBRR( silk_encoder_state *psEncC, /* I/O */ - const silk_EncControlStruct *encControl /* I */ + const opus_int32 TargetRate_bps /* I */ ) { opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR; + opus_int32 LBRR_rate_thres_bps; 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; + psEncC->LBRR_enabled = 0; + if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) { + if( psEncC->fs_kHz == 8 ) { + LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS; + } else if( psEncC->fs_kHz == 12 ) { + LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS; } else { - psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS; + } + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + + if( TargetRate_bps > LBRR_rate_thres_bps ) { + /* 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 ); + } + psEncC->LBRR_enabled = 1; } } diff --git a/thirdparty/opus/silk/debug.h b/thirdparty/opus/silk/debug.h index 6f68c1ca0f..efb6d3e99e 100644 --- a/thirdparty/opus/silk/debug.h +++ b/thirdparty/opus/silk/debug.h @@ -39,10 +39,23 @@ extern "C" 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 +/* make SILK_DEBUG dependent on compiler's _DEBUG */ +#if defined _WIN32 + #ifdef _DEBUG + #define SILK_DEBUG 1 + #else + #define SILK_DEBUG 0 + #endif + + /* overrule the above */ + #if 0 + /* #define NO_ASSERTS*/ + #undef SILK_DEBUG + #define SILK_DEBUG 1 + #endif +#else + #define SILK_DEBUG 0 +#endif /* Flag for using timers */ #define SILK_TIC_TOC 0 diff --git a/thirdparty/opus/silk/dec_API.c b/thirdparty/opus/silk/dec_API.c index 7d5ca7fb9f..b7d8ed48d8 100644 --- a/thirdparty/opus/silk/dec_API.c +++ b/thirdparty/opus/silk/dec_API.c @@ -104,7 +104,7 @@ opus_int silk_Decode( /* O Returns error co int delay_stack_alloc; SAVE_STACK; - celt_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 ); + silk_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 ); /**********************************/ /* Test if first frame in payload */ @@ -143,13 +143,13 @@ opus_int silk_Decode( /* O Returns error co channel_state[ n ].nFramesPerPacket = 3; channel_state[ n ].nb_subfr = 4; } else { - celt_assert( 0 ); + silk_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 ); + silk_assert( 0 ); RESTORE_STACK; return SILK_DEC_INVALID_SAMPLING_FREQUENCY; } diff --git a/thirdparty/opus/silk/decode_core.c b/thirdparty/opus/silk/decode_core.c index 1c352a6522..e569c0e72b 100644 --- a/thirdparty/opus/silk/decode_core.c +++ b/thirdparty/opus/silk/decode_core.c @@ -141,7 +141,7 @@ void silk_decode_core( 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 ); + silk_assert( start_idx > 0 ); if( k == 2 ) { silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); @@ -196,7 +196,7 @@ void silk_decode_core( for( i = 0; i < psDec->subfr_length; i++ ) { /* Short-term prediction */ - celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + silk_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 ] ); @@ -225,6 +225,8 @@ void silk_decode_core( pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); } + /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */ + /* Update LPC filter state */ silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); pexc_Q14 += psDec->subfr_length; diff --git a/thirdparty/opus/silk/decode_frame.c b/thirdparty/opus/silk/decode_frame.c index e73825b267..a605d95ac6 100644 --- a/thirdparty/opus/silk/decode_frame.c +++ b/thirdparty/opus/silk/decode_frame.c @@ -55,7 +55,7 @@ opus_int silk_decode_frame( psDecCtrl->LTP_scale_Q14 = 0; /* Safety checks */ - celt_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + silk_assert( L > 0 && L <= MAX_FRAME_LENGTH ); if( lostFlag == FLAG_DECODE_NORMAL || ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) @@ -91,20 +91,19 @@ opus_int silk_decode_frame( psDec->lossCnt = 0; psDec->prevSignalType = psDec->indices.signalType; - celt_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + silk_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 ); + silk_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 ) ); diff --git a/thirdparty/opus/silk/decode_indices.c b/thirdparty/opus/silk/decode_indices.c index 0bb4a997a5..7afe5c26c1 100644 --- a/thirdparty/opus/silk/decode_indices.c +++ b/thirdparty/opus/silk/decode_indices.c @@ -79,7 +79,7 @@ void silk_decode_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 ); + silk_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 ) { diff --git a/thirdparty/opus/silk/decode_parameters.c b/thirdparty/opus/silk/decode_parameters.c index a56a409858..e345b1dcef 100644 --- a/thirdparty/opus/silk/decode_parameters.c +++ b/thirdparty/opus/silk/decode_parameters.c @@ -52,7 +52,7 @@ void silk_decode_parameters( 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 ); + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order ); /* 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 */ @@ -69,7 +69,7 @@ void silk_decode_parameters( } /* Convert NLSF parameters to AR prediction filter coefficients */ - silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order, psDec->arch ); + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order ); } 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 ) ); diff --git a/thirdparty/opus/silk/decode_pitch.c b/thirdparty/opus/silk/decode_pitch.c index fd1b6bf551..fedbc6a525 100644 --- a/thirdparty/opus/silk/decode_pitch.c +++ b/thirdparty/opus/silk/decode_pitch.c @@ -51,7 +51,7 @@ void silk_decode_pitch( 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 ); + silk_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; } @@ -60,7 +60,7 @@ void silk_decode_pitch( 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 ); + silk_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; } diff --git a/thirdparty/opus/silk/decode_pulses.c b/thirdparty/opus/silk/decode_pulses.c index a56d2d3074..d6bbec9225 100644 --- a/thirdparty/opus/silk/decode_pulses.c +++ b/thirdparty/opus/silk/decode_pulses.c @@ -56,7 +56,7 @@ void silk_decode_pulses( 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 */ + silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ iter++; } diff --git a/thirdparty/opus/silk/decoder_set_fs.c b/thirdparty/opus/silk/decoder_set_fs.c index d9a13d0f0c..eef0fd25e1 100644 --- a/thirdparty/opus/silk/decoder_set_fs.c +++ b/thirdparty/opus/silk/decoder_set_fs.c @@ -40,8 +40,8 @@ opus_int silk_decoder_set_fs( { 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 ); + silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + silk_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 ); @@ -86,7 +86,7 @@ opus_int silk_decoder_set_fs( psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; } else { /* unsupported sampling rate */ - celt_assert( 0 ); + silk_assert( 0 ); } psDec->first_frame_after_reset = 1; psDec->lagPrev = 100; @@ -101,7 +101,7 @@ opus_int silk_decoder_set_fs( } /* Check that settings are valid */ - celt_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); return ret; } diff --git a/thirdparty/opus/silk/define.h b/thirdparty/opus/silk/define.h index 247cb0bf71..19c9b00e25 100644 --- a/thirdparty/opus/silk/define.h +++ b/thirdparty/opus/silk/define.h @@ -46,6 +46,7 @@ extern "C" /* Limits on bitrate */ #define MIN_TARGET_RATE_BPS 5000 #define MAX_TARGET_RATE_BPS 80000 +#define TARGET_RATE_TAB_SZ 8 /* LBRR thresholds */ #define LBRR_NB_MIN_RATE_BPS 12000 @@ -55,12 +56,6 @@ extern "C" /* 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 @@ -152,7 +147,7 @@ extern "C" #define USE_HARM_SHAPING 1 /* Max LPC order of noise shaping filters */ -#define MAX_SHAPE_LPC_ORDER 24 +#define MAX_SHAPE_LPC_ORDER 16 #define HARM_SHAPE_FIR_TAPS 3 @@ -162,7 +157,8 @@ extern "C" #define LTP_BUF_LENGTH 512 #define LTP_MASK ( LTP_BUF_LENGTH - 1 ) -#define DECISION_DELAY 40 +#define DECISION_DELAY 32 +#define DECISION_DELAY_MASK ( DECISION_DELAY - 1 ) /* Number of subframes for excitation entropy coding */ #define SHELL_CODEC_FRAME_LENGTH 16 @@ -177,7 +173,11 @@ extern "C" #define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ +#if( MAX_LPC_ORDER > DECISION_DELAY ) # define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER +#else +# define NSQ_LPC_BUF_LENGTH DECISION_DELAY +#endif /***************************/ /* Voice activity detector */ @@ -205,6 +205,7 @@ extern "C" /******************/ #define NLSF_W_Q 2 #define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_VQ_MAX_SURVIVORS 32 #define NLSF_QUANT_MAX_AMPLITUDE 4 #define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 #define NLSF_QUANT_LEVEL_ADJ 0.1 diff --git a/thirdparty/opus/silk/enc_API.c b/thirdparty/opus/silk/enc_API.c index 55a33f37e9..f8060286db 100644 --- a/thirdparty/opus/silk/enc_API.c +++ b/thirdparty/opus/silk/enc_API.c @@ -82,7 +82,7 @@ opus_int silk_InitEncoder( /* O Returns error co 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 ); + silk_assert( 0 ); } } @@ -91,7 +91,7 @@ opus_int silk_InitEncoder( /* O Returns error co /* Read control structure */ if( ret += silk_QueryEncoder( encState, encStatus ) ) { - celt_assert( 0 ); + silk_assert( 0 ); } return ret; @@ -144,8 +144,7 @@ opus_int silk_Encode( /* O Returns error co 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 */ + const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ ) { opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; @@ -167,7 +166,7 @@ opus_int silk_Encode( /* O Returns error co /* Check values in encoder control structure */ if( ( ret = check_control_input( encControl ) ) != 0 ) { - celt_assert( 0 ); + silk_assert( 0 ); RESTORE_STACK; return ret; } @@ -200,26 +199,16 @@ opus_int silk_Encode( /* O Returns error co 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 ); + silk_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 ); + silk_assert( !ret ); } tmp_payloadSize_ms = encControl->payloadSize_ms; encControl->payloadSize_ms = 10; @@ -232,22 +221,23 @@ opus_int silk_Encode( /* O Returns error co } else { /* Only accept input lengths that are a multiple of 10 ms */ if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { - celt_assert( 0 ); + silk_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 ); + silk_assert( 0 ); RESTORE_STACK; return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; } } + TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 ); 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 ) { + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { silk_assert( 0 ); RESTORE_STACK; return ret; @@ -259,7 +249,7 @@ opus_int silk_Encode( /* O Returns error co } 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 ); + silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); /* Input buffering/resampling and encoding */ nSamplesToBufferMax = @@ -317,7 +307,7 @@ opus_int silk_Encode( /* O Returns error co } psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; } else { - celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_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 ); @@ -333,8 +323,8 @@ opus_int silk_Encode( /* O Returns error co /* 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 ); + silk_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + silk_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 ) { @@ -426,6 +416,7 @@ opus_int silk_Encode( /* O Returns error co /* 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 ].sPrefilt, 0, sizeof( psEnc->state_Fxx[ 1 ].sPrefilt ) ); 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 ) ); @@ -436,7 +427,7 @@ opus_int silk_Encode( /* O Returns error co 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 ); + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] ); } else { psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; } @@ -451,7 +442,7 @@ opus_int silk_Encode( /* O Returns error co 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 ); + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] ); /* Encode */ for( n = 0; n < encControl->nChannelsInternal; n++ ) { @@ -566,10 +557,6 @@ opus_int silk_Encode( /* O Returns error co } } - 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/thirdparty/opus/silk/encode_indices.c b/thirdparty/opus/silk/encode_indices.c index 4bcbc3347b..666c8c0b13 100644 --- a/thirdparty/opus/silk/encode_indices.c +++ b/thirdparty/opus/silk/encode_indices.c @@ -56,8 +56,8 @@ void silk_encode_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 ); + silk_assert( typeOffset >= 0 && typeOffset < 6 ); + silk_assert( encode_LBRR == 0 || typeOffset >= 2 ); if( encode_LBRR || typeOffset >= 2 ) { ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); } else { @@ -90,7 +90,7 @@ void silk_encode_indices( /****************/ 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 ); + silk_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 ); diff --git a/thirdparty/opus/silk/encode_pulses.c b/thirdparty/opus/silk/encode_pulses.c index 8a1999138b..ab00264f99 100644 --- a/thirdparty/opus/silk/encode_pulses.c +++ b/thirdparty/opus/silk/encode_pulses.c @@ -86,7 +86,7 @@ void silk_encode_pulses( 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 */ + silk_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)); } diff --git a/thirdparty/opus/silk/fixed/apply_sine_window_FIX.c b/thirdparty/opus/silk/fixed/apply_sine_window_FIX.c index 03e088a6de..4502b7130e 100644 --- a/thirdparty/opus/silk/fixed/apply_sine_window_FIX.c +++ b/thirdparty/opus/silk/fixed/apply_sine_window_FIX.c @@ -57,15 +57,15 @@ void silk_apply_sine_window( opus_int k, f_Q16, c_Q16; opus_int32 S0_Q16, S1_Q16; - celt_assert( win_type == 1 || win_type == 2 ); + silk_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 ); + silk_assert( length >= 16 && length <= 120 ); + silk_assert( ( length & 3 ) == 0 ); /* Frequency */ k = ( length >> 2 ) - 4; - celt_assert( k >= 0 && k <= 26 ); + silk_assert( k >= 0 && k <= 26 ); f_Q16 = (opus_int)freq_table_Q16[ k ]; /* Factor used for cosine approximation */ diff --git a/thirdparty/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h b/thirdparty/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h deleted file mode 100644 index 1992e43288..0000000000 --- a/thirdparty/opus/silk/fixed/arm/warped_autocorrelation_FIX_arm.h +++ /dev/null @@ -1,68 +0,0 @@ -/*********************************************************************** -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/thirdparty/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c b/thirdparty/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c deleted file mode 100644 index 00a70cb51f..0000000000 --- a/thirdparty/opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c +++ /dev/null @@ -1,260 +0,0 @@ -/*********************************************************************** -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 <arm_neon.h> -#ifdef OPUS_CHECK_ASM -# include <string.h> -#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/thirdparty/opus/silk/fixed/burg_modified_FIX.c b/thirdparty/opus/silk/fixed/burg_modified_FIX.c index 274d4b28e1..17d0e0993c 100644 --- a/thirdparty/opus/silk/fixed/burg_modified_FIX.c +++ b/thirdparty/opus/silk/fixed/burg_modified_FIX.c @@ -37,7 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #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 N_BITS_HEAD_ROOM 2 #define MIN_RSHIFTS -16 #define MAX_RSHIFTS (32 - QA) @@ -65,7 +65,7 @@ void silk_burg_modified_c( opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; opus_int64 C0_64; - celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + silk_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 ); diff --git a/thirdparty/opus/silk/fixed/corrMatrix_FIX.c b/thirdparty/opus/silk/fixed/corrMatrix_FIX.c index 1b4a29c232..c1d437c785 100644 --- a/thirdparty/opus/silk/fixed/corrMatrix_FIX.c +++ b/thirdparty/opus/silk/fixed/corrMatrix_FIX.c @@ -58,7 +58,7 @@ void silk_corrVector_FIX( 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 ); + inner_prod += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); } Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ ptr1--; /* Go to next column of X */ @@ -77,54 +77,61 @@ 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 */ + const opus_int head_room, /* I Desired headroom */ 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 */ + opus_int *rshifts, /* I/O Right shifts of correlations */ int arch /* I Run-time architecture */ ) { - opus_int i, j, lag; + opus_int i, j, lag, rshifts_local, head_room_rshifts; 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; + silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 ); + /* Add shifts to get the desired head room */ + head_room_rshifts = silk_max( head_room - silk_CLZ32( energy ), 0 ); + + energy = silk_RSHIFT32( energy, head_room_rshifts ); + rshifts_local += head_room_rshifts; /* 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 ); + energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), rshifts_local ); + } + if( rshifts_local < *rshifts ) { + /* Adjust energy */ + energy = silk_RSHIFT32( energy, *rshifts - rshifts_local ); + rshifts_local = *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 ) ); + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) ); 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 ) { + if( rshifts_local > 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 ); + energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local ); } /* 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 ) ); + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) ); matrix_ptr( XX, lag + j, j, order ) = energy; matrix_ptr( XX, j, lag + j, order ) = energy; } @@ -146,5 +153,6 @@ void silk_corrMatrix_FIX( ptr2--;/* Update pointer to first sample of next column (lag) in X */ } } + *rshifts = rshifts_local; } diff --git a/thirdparty/opus/silk/fixed/encode_frame_FIX.c b/thirdparty/opus/silk/fixed/encode_frame_FIX.c index a02bf87dbb..5ef44b03fc 100644 --- a/thirdparty/opus/silk/fixed/encode_frame_FIX.c +++ b/thirdparty/opus/silk/fixed/encode_frame_FIX.c @@ -29,7 +29,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "config.h" #endif -#include <stdlib.h> #include "main_FIX.h" #include "stack_alloc.h" #include "tuning_parameters.h" @@ -38,33 +37,26 @@ POSSIBILITY OF SUCH DAMAGE. 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 */ + const opus_int32 xfw_Q3[], /* 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 */ + silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ ) { - 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 ) { + if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; psEnc->sCmn.noSpeechCounter++; - if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + 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; @@ -102,9 +94,6 @@ opus_int silk_encode_frame_FIX( 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 */ @@ -129,6 +118,7 @@ opus_int silk_encode_frame_FIX( 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_int32, xfw_Q3 ); VARDECL( opus_int16, res_pitch ); VARDECL( opus_uint8, ec_buf_copy ); opus_int16 *res_pitch_frame; @@ -142,7 +132,7 @@ opus_int silk_encode_frame_FIX( /*****************************************/ /* 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 ); + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch ); /************************/ /* Noise shape analysis */ @@ -152,17 +142,23 @@ opus_int silk_encode_frame_FIX( /***************************************************/ /* Find linear prediction coefficients (LPC + LTP) */ /***************************************************/ - silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); /****************************************/ /* Process gains */ /****************************************/ silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + ALLOC( xfw_Q3, psEnc->sCmn.frame_length, opus_int32 ); + silk_prefilter_FIX( psEnc, &sEncCtrl, xfw_Q3, x_frame ); + /****************************************/ /* Low Bitrate Redundant Encoding */ /****************************************/ - silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding ); + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw_Q3, condCoding ); /* Loop over quantizer and entropy coding to control bitrate */ maxIter = 6; @@ -198,21 +194,17 @@ opus_int silk_encode_frame_FIX( /* 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, + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, 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, + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, psEnc->sCmn.arch); } - if ( iter == maxIter && !found_lower ) { - silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); - } - /****************************************/ /* Encode Parameters */ /****************************************/ @@ -226,33 +218,6 @@ opus_int silk_encode_frame_FIX( 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; } @@ -262,7 +227,7 @@ opus_int silk_encode_frame_FIX( 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_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; @@ -290,7 +255,7 @@ opus_int silk_encode_frame_FIX( gainsID_lower = gainsID; /* Copy part of the output state */ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); - celt_assert( psRangeEnc->offs <= 1275 ); + silk_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; @@ -300,35 +265,15 @@ opus_int silk_encode_frame_FIX( 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 */ + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); 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 ); + gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); } - + 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 ); @@ -342,13 +287,7 @@ opus_int silk_encode_frame_FIX( } 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 ); + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); } /* Quantize gains */ @@ -392,7 +331,7 @@ opus_int silk_encode_frame_FIX( 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 */ + const opus_int32 xfw_Q3[], /* I Input signal */ opus_int condCoding /* I The type of conditional coding used so far for this frame */ ) { @@ -431,14 +370,14 @@ static OPUS_INLINE void silk_LBRR_encode_FIX( /* Noise shaping quantization */ /*****************************************/ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { - silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3, 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->AR2_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, + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3, 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->AR2_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 ); } diff --git a/thirdparty/opus/silk/fixed/find_LPC_FIX.c b/thirdparty/opus/silk/fixed/find_LPC_FIX.c index c762a0f2a2..e11cdc86e6 100644 --- a/thirdparty/opus/silk/fixed/find_LPC_FIX.c +++ b/thirdparty/opus/silk/fixed/find_LPC_FIX.c @@ -92,7 +92,7 @@ void silk_find_LPC_FIX( 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 ); + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder ); /* Calculate residual energy with NLSF interpolation */ silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch ); @@ -146,6 +146,6 @@ void silk_find_LPC_FIX( 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 ) ); + silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); RESTORE_STACK; } diff --git a/thirdparty/opus/silk/fixed/find_LTP_FIX.c b/thirdparty/opus/silk/fixed/find_LTP_FIX.c index 62d4afb250..1314a28137 100644 --- a/thirdparty/opus/silk/fixed/find_LTP_FIX.c +++ b/thirdparty/opus/silk/fixed/find_LTP_FIX.c @@ -32,68 +32,214 @@ POSSIBILITY OF SUCH DAMAGE. #include "main_FIX.h" #include "tuning_parameters.h" +/* Head room for correlations */ +#define LTP_CORRS_HEAD_ROOM 2 + +void silk_fit_LTP( + opus_int32 LTP_coefs_Q16[ LTP_ORDER ], + opus_int16 LTP_coefs_Q14[ LTP_ORDER ] +); + 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 */ + opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ 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 */ + const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ + const opus_int subfr_length, /* I subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset, /* I number of samples in LTP memory */ + opus_int corr_rshifts[ MAX_NB_SUBFR ], /* O right shifts applied to correlations */ 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; + opus_int i, k, lshift; + const opus_int16 *r_ptr, *lag_ptr; + opus_int16 *b_Q14_ptr; + + opus_int32 regu; + opus_int32 *WLTP_ptr; + opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26; + opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits; + + opus_int32 temp32, denom32; + opus_int extra_shifts; + opus_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs; + opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16; + opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; + opus_int32 wd, m_Q12; + + b_Q14_ptr = b_Q14; + WLTP_ptr = WLTP; + r_ptr = &r_lpc[ mem_offset ]; 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_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */ + + /* Assure headroom */ + LZs = silk_CLZ32( rr[k] ); + if( LZs < LTP_CORRS_HEAD_ROOM ) { + rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs ); + rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs ); } - silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */ + corr_rshifts[ k ] = rr_shifts; + silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ], arch ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */ + + /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */ + silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ], arch ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */ + if( corr_rshifts[ k ] > rr_shifts ) { + rr[ k ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */ + } + silk_assert( rr[ k ] >= 0 ); + + regu = 1; + regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER ); + + silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */ + + /* Limit and store in Q14 */ + silk_fit_LTP( b_Q16, b_Q14_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */ + + /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */ + extra_shifts = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM ); + denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + silk_RSHIFT( silk_SMULWB( (opus_int32)subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + denom32 = silk_max( denom32, 1 ); + silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX ); /* Wght always < 0.5 in Q0 */ + temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */ + temp32 = silk_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */ - /* 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 + /* Limit temp such that the below scaling never wraps around */ + WLTP_max = 0; for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { - XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 ); + WLTP_max = silk_max( WLTP_ptr[ i ], WLTP_max ); } + lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */ + silk_assert( 26 - 18 + lshift >= 0 ); + if( 26 - 18 + lshift < 31 ) { + temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) ); + } + + silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */ + + w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */ + silk_assert( w[k] >= 0 ); + + r_ptr += subfr_length; + b_Q14_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + maxRshifts = 0; + for( k = 0; k < nb_subfr; k++ ) { + maxRshifts = silk_max_int( corr_rshifts[ k ], maxRshifts ); + } + + /* Compute LTP coding gain */ + if( LTPredCodGain_Q7 != NULL ) { + LPC_LTP_res_nrg = 0; + LPC_res_nrg = 0; + silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */ + for( k = 0; k < nb_subfr; k++ ) { + LPC_res_nrg = silk_ADD32( LPC_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + } + LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */ + + div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 ); + *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ); + + silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) ); + } + + /* smoothing */ + /* d = sum( B, 1 ); */ + b_Q14_ptr = b_Q14; + for( k = 0; k < nb_subfr; k++ ) { + d_Q14[ k ] = 0; for( i = 0; i < LTP_ORDER; i++ ) { - xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 ); + d_Q14[ k ] += b_Q14_ptr[ i ]; } -#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 ); + b_Q14_ptr += LTP_ORDER; + } + + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + + /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */ + max_abs_d_Q14 = 0; + max_w_bits = 0; + for( k = 0; k < nb_subfr; k++ ) { + max_abs_d_Q14 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) ); + /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */ + /* Find bits needed in Q( 18 - maxRshifts ) */ + max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts ); + } + + /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */ + silk_assert( max_abs_d_Q14 <= ( 5 << 15 ) ); + + /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */ + extra_shifts = max_w_bits + 32 - silk_CLZ32( max_abs_d_Q14 ) - 14; + + /* Subtract what we got available; bits in output var plus maxRshifts */ + extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */ + extra_shifts = silk_max_int( extra_shifts, 0 ); + + maxRshifts_wxtra = maxRshifts + extra_shifts; + + temp32 = silk_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */ + wd = 0; + for( k = 0; k < nb_subfr; k++ ) { + /* w has at least 2 bits of headroom so no overflow should happen */ + temp32 = silk_ADD32( temp32, silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */ + wd = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */ + } + m_Q12 = silk_DIV32_varQ( wd, temp32, 12 ); + + b_Q14_ptr = b_Q14; + for( k = 0; k < nb_subfr; k++ ) { + /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */ + if( 2 - corr_rshifts[k] > 0 ) { + temp32 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] ); + } else { + temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 ); } + + g_Q26 = silk_MUL( + silk_DIV32( + SILK_FIX_CONST( LTP_SMOOTHING, 26 ), + silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */ + silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */ + + temp32 = 0; for( i = 0; i < LTP_ORDER; i++ ) { - xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp ); + delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */ + temp32 += delta_b_Q14[ i ]; /* Q14 */ } -#endif -TOC(div) - r_ptr += subfr_length; - XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER; - xXLTP_Q17_ptr += LTP_ORDER; + temp32 = silk_DIV32( g_Q26, temp32 ); /* Q14 -> Q12 */ + for( i = 0; i < LTP_ORDER; i++ ) { + b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 ); + } + b_Q14_ptr += LTP_ORDER; + } +} + +void silk_fit_LTP( + opus_int32 LTP_coefs_Q16[ LTP_ORDER ], + opus_int16 LTP_coefs_Q14[ LTP_ORDER ] +) +{ + opus_int i; + + for( i = 0; i < LTP_ORDER; i++ ) { + LTP_coefs_Q14[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) ); } } diff --git a/thirdparty/opus/silk/fixed/find_pitch_lags_FIX.c b/thirdparty/opus/silk/fixed/find_pitch_lags_FIX.c index 6c3379f2bb..b8440a8247 100644 --- a/thirdparty/opus/silk/fixed/find_pitch_lags_FIX.c +++ b/thirdparty/opus/silk/fixed/find_pitch_lags_FIX.c @@ -44,7 +44,7 @@ void silk_find_pitch_lags_FIX( { opus_int buf_len, i, scale; opus_int32 thrhld_Q13, res_nrg; - const opus_int16 *x_ptr; + const opus_int16 *x_buf, *x_buf_ptr; VARDECL( opus_int16, Wsig ); opus_int16 *Wsig_ptr; opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; @@ -59,7 +59,9 @@ void silk_find_pitch_lags_FIX( 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 ); + silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; /*************************************/ /* Estimate LPC AR coefficients */ @@ -70,19 +72,19 @@ void silk_find_pitch_lags_FIX( 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; + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; Wsig_ptr = Wsig; - silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch ); + silk_apply_sine_window( Wsig_ptr, x_buf_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 ) ); + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_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 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_buf_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 ); @@ -110,7 +112,7 @@ void silk_find_pitch_lags_FIX( /*****************************************/ /* LPC analysis filtering */ /*****************************************/ - silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch ); + silk_LPC_analysis_filter( res, x_buf, 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 */ diff --git a/thirdparty/opus/silk/fixed/find_pred_coefs_FIX.c b/thirdparty/opus/silk/fixed/find_pred_coefs_FIX.c index 606d863347..d308e9cf5f 100644 --- a/thirdparty/opus/silk/fixed/find_pred_coefs_FIX.c +++ b/thirdparty/opus/silk/fixed/find_pred_coefs_FIX.c @@ -41,12 +41,13 @@ void silk_find_pred_coefs_FIX( ) { opus_int i; - opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ]; + opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ 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; + opus_int32 tmp, min_gain_Q16, minInvGain_Q30; + opus_int LTP_corrs_rshift[ MAX_NB_SUBFR ]; SAVE_STACK; /* weighting for weighted least squares */ @@ -60,11 +61,13 @@ void silk_find_pred_coefs_FIX( /* 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 ); + /* Ensure Wght_Q15 a minimum value 1 */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 ); /* Square the inverted gains */ silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] ); + Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 ); /* Invert the inverted and normalized gains */ local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); @@ -74,24 +77,24 @@ void silk_find_pred_coefs_FIX( 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 ); + VARDECL( opus_int32, WLTP ); /**********/ /* VOICED */ /**********/ - celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + silk_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 ); + ALLOC( WLTP, 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 ); + silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7, + res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length, + psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift, 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 ); + &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr, + psEnc->sCmn.arch); /* Control LTP scaling */ silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); diff --git a/thirdparty/opus/silk/fixed/k2a_FIX.c b/thirdparty/opus/silk/fixed/k2a_FIX.c index 549f6eadaa..5fee599bcb 100644 --- a/thirdparty/opus/silk/fixed/k2a_FIX.c +++ b/thirdparty/opus/silk/fixed/k2a_FIX.c @@ -39,15 +39,14 @@ void silk_k2a( ) { opus_int k, n; - opus_int32 rc, tmp1, tmp2; + opus_int32 Atmp[ SILK_MAX_ORDER_LPC ]; 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 ); + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = silk_SMLAWB( A_Q24[ n ], silk_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] ); } A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); } diff --git a/thirdparty/opus/silk/fixed/k2a_Q16_FIX.c b/thirdparty/opus/silk/fixed/k2a_Q16_FIX.c index 1595aa6212..3b03987544 100644 --- a/thirdparty/opus/silk/fixed/k2a_Q16_FIX.c +++ b/thirdparty/opus/silk/fixed/k2a_Q16_FIX.c @@ -39,16 +39,15 @@ void silk_k2a_Q16( ) { opus_int k, n; - opus_int32 rc, tmp1, tmp2; + opus_int32 Atmp[ SILK_MAX_ORDER_LPC ]; 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 ); + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; } - A_Q24[ k ] = -silk_LSHIFT( rc, 8 ); + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = silk_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] ); + } + A_Q24[ k ] = -silk_LSHIFT( rc_Q16[ k ], 8 ); } } diff --git a/thirdparty/opus/silk/fixed/main_FIX.h b/thirdparty/opus/silk/fixed/main_FIX.h index 6d2112e511..375b5eb32e 100644 --- a/thirdparty/opus/silk/fixed/main_FIX.h +++ b/thirdparty/opus/silk/fixed/main_FIX.h @@ -36,11 +36,6 @@ POSSIBILITY OF SUCH DAMAGE. #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" @@ -52,9 +47,6 @@ extern "C" #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 */ /*********************/ @@ -66,8 +58,7 @@ void silk_HP_variable_cutoff( /* 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 */ + silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ ); /* Encoder main function */ @@ -90,11 +81,33 @@ opus_int silk_init_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_int32 TargetRate_bps, /* I Target max bitrate (bps) */ 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 ); +/****************/ +/* Prefiltering */ +/****************/ +void silk_prefilter_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + opus_int32 xw_Q10[], /* O Weighted signal */ + const opus_int16 x[] /* I Speech signal */ +); + +void silk_warped_LPC_analysis_filter_FIX_c( + 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) */ +); + + /**************************/ /* Noise shaping analysis */ /**************************/ @@ -108,7 +121,7 @@ void silk_noise_shape_analysis_FIX( ); /* Autocorrelations for a warped frequency axis */ -void silk_warped_autocorrelation_FIX_c( +void silk_warped_autocorrelation_FIX( 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 */ @@ -117,11 +130,6 @@ void silk_warped_autocorrelation_FIX_c( 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 */ @@ -160,12 +168,16 @@ void silk_find_LPC_FIX( /* 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 */ + opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ 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 */ + const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ + const opus_int subfr_length, /* I subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset, /* I number of samples in LTP memory */ + opus_int corr_rshifts[ MAX_NB_SUBFR ], /* O right shifts applied to correlations */ int arch /* I Run-time architecture */ ); @@ -219,9 +231,9 @@ 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 */ + const opus_int head_room, /* I Desired headroom */ 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 */ + opus_int *rshifts, /* I/O Right shifts of correlations */ int arch /* I Run-time architecture */ ); @@ -236,6 +248,22 @@ void silk_corrVector_FIX( int arch /* I Run-time architecture */ ); +/* 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 */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void silk_solve_LDL_FIX( + opus_int32 *A, /* I Pointer to symetric square matrix A */ + opus_int M, /* I Size of matrix */ + const opus_int32 *b, /* I Pointer to b vector */ + opus_int32 *x_Q16 /* O Pointer to x solution vector */ +); + #ifndef FORCE_CPP_BUILD #ifdef __cplusplus } diff --git a/thirdparty/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h b/thirdparty/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h index 3999b5bd09..c30481e437 100644 --- a/thirdparty/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h +++ b/thirdparty/opus/silk/fixed/mips/noise_shape_analysis_FIX_mipsr1.h @@ -169,7 +169,7 @@ void silk_noise_shape_analysis_FIX( 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 ); + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); } else { /* Calculate regular auto correlation */ silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); @@ -224,8 +224,8 @@ void silk_noise_shape_analysis_FIX( 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 ); + pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder ); + nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder ); /*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 ); diff --git a/thirdparty/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h b/thirdparty/opus/silk/fixed/mips/prefilter_FIX_mipsr1.h new file mode 100644 index 0000000000..21b256885f --- /dev/null +++ b/thirdparty/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/thirdparty/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h b/thirdparty/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h index 66eb2ed26d..e803ef0fce 100644 --- a/thirdparty/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h +++ b/thirdparty/opus/silk/fixed/mips/warped_autocorrelation_FIX_mipsr1.h @@ -41,8 +41,8 @@ POSSIBILITY OF SUCH DAMAGE. #define QS 14 /* Autocorrelations for a warped frequency axis */ -#define OVERRIDE_silk_warped_autocorrelation_FIX_c -void silk_warped_autocorrelation_FIX_c( +#define OVERRIDE_silk_warped_autocorrelation_FIX +void silk_warped_autocorrelation_FIX( 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 */ diff --git a/thirdparty/opus/silk/fixed/noise_shape_analysis_FIX.c b/thirdparty/opus/silk/fixed/noise_shape_analysis_FIX.c index 85fea0bf09..22a89f75ae 100644 --- a/thirdparty/opus/silk/fixed/noise_shape_analysis_FIX.c +++ b/thirdparty/opus/silk/fixed/noise_shape_analysis_FIX.c @@ -57,79 +57,88 @@ static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/ /* 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_int32 *coefs_syn_Q24, + opus_int32 *coefs_ana_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 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_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 ); + coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_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 ); + 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_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_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 ] ); + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_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 ] ); + tmp = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), silk_abs_int32( coefs_ana_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 ) { + if( maxabs_Q24 <= limit_Q24 ) { /* 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 ); + coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); } - gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 ); + gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 ); + gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 ); for( i = 0; i < order; i++ ) { - coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_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 ); + silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q24, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); + silk_bwexpander_32( coefs_ana_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 ); + coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_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 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_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 ] ); + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); } } silk_assert( 0 ); } -/* Disable MIPS version until it's updated. */ -#if 0 && defined(MIPSr1_ASM) +#if defined(MIPSr1_ASM) #include "mips/noise_shape_analysis_FIX_mipsr1.h" #endif @@ -146,13 +155,14 @@ void silk_noise_shape_analysis_FIX( ) { 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_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 AR_Q24[ 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; @@ -199,14 +209,14 @@ void silk_noise_shape_analysis_FIX( 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; - nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; - for( k = 0; k < nSegs; k++ ) { + 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)*/ @@ -218,12 +228,18 @@ void silk_noise_shape_analysis_FIX( 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( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) { + 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 ) ); } /*******************************/ @@ -231,8 +247,14 @@ void silk_noise_shape_analysis_FIX( /*******************************/ /* 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 ), + 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 */ @@ -262,7 +284,7 @@ void silk_noise_shape_analysis_FIX( 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 ); + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); } else { /* Calculate regular auto correlation */ silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); @@ -277,7 +299,7 @@ void silk_noise_shape_analysis_FIX( silk_assert( nrg >= 0 ); /* Convert reflection coefficients to prediction coefficients */ - silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); Qnrg = -scale; /* range: -12...30*/ silk_assert( Qnrg >= -12 ); @@ -296,34 +318,40 @@ void silk_noise_shape_analysis_FIX( 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 ); + 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( 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 ); - } + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); } - silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); } - /* Bandwidth expansion */ - silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 ); + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_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 ); + /* Compute noise shaping filter coefficients */ + silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) ); - /* 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 ); + /* 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 ); + nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder ); + + /*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 ) ); } } @@ -340,6 +368,11 @@ void silk_noise_shape_analysis_FIX( 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 */ @@ -377,6 +410,14 @@ void silk_noise_shape_analysis_FIX( /****************************/ /* 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 ), @@ -394,11 +435,14 @@ void silk_noise_shape_analysis_FIX( /* 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 ); } diff --git a/thirdparty/opus/silk/fixed/pitch_analysis_core_FIX.c b/thirdparty/opus/silk/fixed/pitch_analysis_core_FIX.c index 14729046d2..01bb9fc0a8 100644 --- a/thirdparty/opus/silk/fixed/pitch_analysis_core_FIX.c +++ b/thirdparty/opus/silk/fixed/pitch_analysis_core_FIX.c @@ -80,7 +80,7 @@ static void silk_P_Ana_calc_energy_st3( /* 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 */ + 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 */ @@ -94,17 +94,16 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 int arch /* I Run-time architecture */ ) { - VARDECL( opus_int16, frame_8kHz_buf ); + VARDECL( opus_int16, frame_8kHz ); VARDECL( opus_int16, frame_4kHz ); - VARDECL( opus_int16, frame_scaled ); opus_int32 filt_state[ 6 ]; - const opus_int16 *frame, *frame_8kHz; + const opus_int16 *input_frame_ptr; 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; + opus_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp; 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; @@ -120,13 +119,12 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 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 ); + silk_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( complexity >= SILK_PE_MIN_COMPLEX ); + silk_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) ); @@ -139,33 +137,17 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 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 */ + ALLOC( frame_8kHz, frame_length_8kHz, opus_int16 ); 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; + silk_resampler_down2( filt_state, frame_8kHz, frame, frame_length ); } 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; + silk_resampler_down2_3( filt_state, frame_8kHz, frame, frame_length ); } else { - celt_assert( Fs_kHz == 8 ); - frame_8kHz = frame; + silk_assert( Fs_kHz == 8 ); + silk_memcpy( frame_8kHz, frame, frame_length_8kHz * sizeof(opus_int16) ); } /* Decimate again to 4 kHz */ @@ -178,6 +160,19 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); } + /******************************************************************************* + ** Scale 4 kHz signal down to prevent correlations measures from overflowing + ** find scaling as max scaling for each 8kHz(?) subframe + *******************************************************************************/ + + /* Inner product is calculated with different lengths, so scale for the worst case */ + silk_sum_sqr_shift( &energy, &shift, frame_4kHz, frame_length_4kHz ); + if( shift > 0 ) { + shift = silk_RSHIFT( shift, 1 ); + for( i = 0; i < frame_length_4kHz; i++ ) { + frame_4kHz[ i ] = silk_RSHIFT( frame_4kHz[ i ], shift ); + } + } /****************************************************************************** * FIRST STAGE, operating in 4 khz @@ -188,14 +183,14 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 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 ); + silk_assert( target_ptr >= frame_4kHz ); + silk_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 ); + silk_assert( basis_ptr >= frame_4kHz ); + silk_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 ); @@ -249,7 +244,7 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 /* Sort */ length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); - celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ, length_d_srch ); @@ -274,7 +269,7 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 break; } } - celt_assert( length_d_srch > 0 ); + silk_assert( length_d_srch > 0 ); ALLOC( d_comp, D_COMP_STRIDE, opus_int16 ); for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) { @@ -316,6 +311,18 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation *************************************************************************************/ + /****************************************************************************** + ** Scale signal down to avoid correlations measures from overflowing + *******************************************************************************/ + /* find scaling as max scaling for each subframe */ + silk_sum_sqr_shift( &energy, &shift, frame_8kHz, frame_length_8kHz ); + if( shift > 0 ) { + shift = silk_RSHIFT( shift, 1 ); + for( i = 0; i < frame_length_8kHz; i++ ) { + frame_8kHz[ i ] = silk_RSHIFT( frame_8kHz[ i ], shift ); + } + } + /********************************************************************************* * Find energy of each subframe projected onto its history, for a range of delays *********************************************************************************/ @@ -325,8 +332,8 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 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 ); + silk_assert( target_ptr >= frame_8kHz ); + silk_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++ ) { @@ -455,6 +462,24 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 silk_assert( *LTPCorr_Q15 >= 0 ); if( Fs_kHz > 8 ) { + VARDECL( opus_int16, scratch_mem ); + /***************************************************************************/ + /* Scale input signal down to avoid correlations measures from overflowing */ + /***************************************************************************/ + /* find scaling as max scaling for each subframe */ + silk_sum_sqr_shift( &energy, &shift, frame, frame_length ); + ALLOC( scratch_mem, shift > 0 ? frame_length : ALLOC_NONE, opus_int16 ); + if( shift > 0 ) { + /* Move signal to scratch mem because the input signal should be unchanged */ + shift = silk_RSHIFT( shift, 1 ); + for( i = 0; i < frame_length; i++ ) { + scratch_mem[ i ] = silk_RSHIFT( frame[ i ], shift ); + } + input_frame_ptr = scratch_mem; + } else { + input_frame_ptr = frame; + } + /* Search in original signal */ CBimax_old = CBimax; @@ -494,14 +519,14 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 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 ); + silk_P_Ana_calc_corr_st3( cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, input_frame_ptr, 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 ]; + target_ptr = &input_frame_ptr[ 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++ ) { @@ -550,7 +575,7 @@ opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ ); *contourIndex = (opus_int8)CBimax; } - celt_assert( *lagIndex >= 0 ); + silk_assert( *lagIndex >= 0 ); /* return as voiced */ RESTORE_STACK; return 0; @@ -587,8 +612,8 @@ static void silk_P_Ana_calc_corr_st3( 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 ); + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); if( nb_subfr == PE_MAX_NB_SUBFR ) { Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; @@ -596,7 +621,7 @@ static void silk_P_Ana_calc_corr_st3( 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); + silk_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; @@ -612,7 +637,7 @@ static void silk_P_Ana_calc_corr_st3( /* 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); + silk_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 ); @@ -659,8 +684,8 @@ static void silk_P_Ana_calc_energy_st3( 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 ); + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); if( nb_subfr == PE_MAX_NB_SUBFR ) { Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; @@ -668,7 +693,7 @@ static void silk_P_Ana_calc_energy_st3( 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); + silk_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; diff --git a/thirdparty/opus/silk/fixed/prefilter_FIX.c b/thirdparty/opus/silk/fixed/prefilter_FIX.c new file mode 100644 index 0000000000..6a8e35152e --- /dev/null +++ b/thirdparty/opus/silk/fixed/prefilter_FIX.c @@ -0,0 +1,221 @@ +/*********************************************************************** +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" + +#if defined(MIPSr1_ASM) +#include "mips/prefilter_FIX_mipsr1.h" +#endif + + +#if !defined(OVERRIDE_silk_warped_LPC_analysis_filter_FIX) +#define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \ + ((void)(arch),silk_warped_LPC_analysis_filter_FIX_c(state, res_Q2, coef_Q13, input, lambda_Q16, length, order)) +#endif + +/* Prefilter for finding Quantizer input signal */ +static OPUS_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 */ +); + +void silk_warped_LPC_analysis_filter_FIX_c( + 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 */ + silk_assert( ( order & 1 ) == 0 ); + + 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 ); + } +} + +void silk_prefilter_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + opus_int32 xw_Q3[], /* O Weighted signal */ + const opus_int16 x[] /* I Speech signal */ +) +{ + silk_prefilter_state_FIX *P = &psEnc->sPrefilt; + opus_int j, k, lag; + opus_int32 tmp_32; + const opus_int16 *AR1_shp_Q13; + const opus_int16 *px; + opus_int32 *pxw_Q3; + opus_int HarmShapeGain_Q12, Tilt_Q14; + opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14; + VARDECL( opus_int32, x_filt_Q12 ); + VARDECL( opus_int32, st_res_Q2 ); + opus_int16 B_Q10[ 2 ]; + SAVE_STACK; + + /* Set up pointers */ + px = x; + pxw_Q3 = xw_Q3; + lag = P->lagPrev; + ALLOC( x_filt_Q12, psEnc->sCmn.subfr_length, opus_int32 ); + ALLOC( st_res_Q2, psEnc->sCmn.subfr_length, opus_int32 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Update Variables that change per sub frame */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + lag = psEncCtrl->pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain_Q12 = silk_SMULWB( (opus_int32)psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] ); + silk_assert( HarmShapeGain_Q12 >= 0 ); + HarmShapeFIRPacked_Q12 = silk_RSHIFT( HarmShapeGain_Q12, 2 ); + HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q12, 1 ), 16 ); + Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ]; + LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ]; + AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering*/ + silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px, + psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder, psEnc->sCmn.arch ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 ); + tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 ); /* Q10 */ + B_Q10[ 1 ]= silk_SAT16( tmp_32 ); + x_filt_Q12[ 0 ] = silk_MLA( silk_MUL( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = silk_MLA( silk_MUL( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] ); + } + P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ]; + + silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw_Q3 += psEnc->sCmn.subfr_length; + } + + P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + RESTORE_STACK; +} + +#ifndef OVERRIDE_silk_prefilt_FIX +/* Prefilter for finding Quantizer input signal */ +static OPUS_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; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + /* 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 ); + } else { + 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( silk_SUB32( sLF_MA_shp_Q12, n_LTP_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 /* OVERRIDE_silk_prefilt_FIX */ diff --git a/thirdparty/opus/silk/fixed/residual_energy16_FIX.c b/thirdparty/opus/silk/fixed/residual_energy16_FIX.c index 7f130f3d3d..ebffb2a66f 100644 --- a/thirdparty/opus/silk/fixed/residual_energy16_FIX.c +++ b/thirdparty/opus/silk/fixed/residual_energy16_FIX.c @@ -47,10 +47,10 @@ opus_int32 silk_residual_energy16_covar_FIX( const opus_int32 *pRow; /* Safety checks */ - celt_assert( D >= 0 ); - celt_assert( D <= 16 ); - celt_assert( cQ > 0 ); - celt_assert( cQ < 16 ); + silk_assert( D >= 0 ); + silk_assert( D <= 16 ); + silk_assert( cQ > 0 ); + silk_assert( cQ < 16 ); lshifts = 16 - cQ; Qxtra = lshifts; diff --git a/thirdparty/opus/silk/fixed/residual_energy_FIX.c b/thirdparty/opus/silk/fixed/residual_energy_FIX.c index 6c7cade9a0..41f74778e8 100644 --- a/thirdparty/opus/silk/fixed/residual_energy_FIX.c +++ b/thirdparty/opus/silk/fixed/residual_energy_FIX.c @@ -58,7 +58,7 @@ void silk_residual_energy_FIX( /* 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 ); + silk_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 ); diff --git a/thirdparty/opus/silk/fixed/schur64_FIX.c b/thirdparty/opus/silk/fixed/schur64_FIX.c index 4b7e19ea59..764a10ef3e 100644 --- a/thirdparty/opus/silk/fixed/schur64_FIX.c +++ b/thirdparty/opus/silk/fixed/schur64_FIX.c @@ -43,7 +43,7 @@ opus_int32 silk_schur64( /* O returns residual ene 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 ); + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); /* Check for invalid input */ if( c[ 0 ] <= 0 ) { @@ -51,10 +51,9 @@ opus_int32 silk_schur64( /* O returns residual ene return 0; } - k = 0; - do { + for( k = 0; k < order + 1; k++ ) { 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. */ diff --git a/thirdparty/opus/silk/fixed/schur_FIX.c b/thirdparty/opus/silk/fixed/schur_FIX.c index 2840f6b1aa..c4c0ef23b4 100644 --- a/thirdparty/opus/silk/fixed/schur_FIX.c +++ b/thirdparty/opus/silk/fixed/schur_FIX.c @@ -43,29 +43,28 @@ opus_int32 silk_schur( /* O Returns residual ene 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 ); + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); /* 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 { + for( k = 0; k < order + 1; k++ ) { 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 { + for( k = 0; k < order + 1; k++ ) { C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz ); - } while( ++k <= order ); + } } else { /* No need to shift */ - do { + for( k = 0; k < order + 1; k++ ) { C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; - } while( ++k <= order ); + } } for( k = 0; k < order; k++ ) { diff --git a/thirdparty/opus/silk/fixed/solve_LS_FIX.c b/thirdparty/opus/silk/fixed/solve_LS_FIX.c new file mode 100644 index 0000000000..51d7d49d02 --- /dev/null +++ b/thirdparty/opus/silk/fixed/solve_LS_FIX.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 "main_FIX.h" +#include "stack_alloc.h" +#include "tuning_parameters.h" + +/*****************************/ +/* Internal function headers */ +/*****************************/ + +typedef struct { + opus_int32 Q36_part; + opus_int32 Q48_part; +} inv_D_t; + +/* Factorize square matrix A into LDL form */ +static OPUS_INLINE void silk_LDL_factorize_FIX( + opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +); + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +static OPUS_INLINE void silk_LS_SolveFirst_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +); + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +static OPUS_INLINE void silk_LS_SolveLast_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +); + +static OPUS_INLINE void silk_LS_divide_Q16_FIX( + opus_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + opus_int M /* I dimension */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void silk_solve_LDL_FIX( + opus_int32 *A, /* I Pointer to symetric square matrix A */ + opus_int M, /* I Size of matrix */ + const opus_int32 *b, /* I Pointer to b vector */ + opus_int32 *x_Q16 /* O Pointer to x solution vector */ +) +{ + VARDECL( opus_int32, L_Q16 ); + opus_int32 Y[ MAX_MATRIX_SIZE ]; + inv_D_t inv_D[ MAX_MATRIX_SIZE ]; + SAVE_STACK; + + silk_assert( M <= MAX_MATRIX_SIZE ); + ALLOC( L_Q16, M * M, opus_int32 ); + + /*************************************************** + Factorize A by LDL such that A = L*D*L', + where L is lower triangular with ones on diagonal + ****************************************************/ + silk_LDL_factorize_FIX( A, M, L_Q16, inv_D ); + + /**************************************************** + * substitute D*L'*x = Y. ie: + L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b + ******************************************************/ + silk_LS_SolveFirst_FIX( L_Q16, M, b, Y ); + + /**************************************************** + D*L'*x = Y <=> L'*x = inv(D)*Y, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + silk_LS_divide_Q16_FIX( Y, inv_D, M ); + + /**************************************************** + x = inv(L') * inv(D) * Y + *****************************************************/ + silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 ); + RESTORE_STACK; +} + +static OPUS_INLINE void silk_LDL_factorize_FIX( + opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +) +{ + opus_int i, j, k, status, loop_count; + const opus_int32 *ptr1, *ptr2; + opus_int32 diag_min_value, tmp_32, err; + opus_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ]; + opus_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48; + + silk_assert( M <= MAX_MATRIX_SIZE ); + + status = 1; + diag_min_value = silk_max_32( silk_SMMUL( silk_ADD_SAT32( A[ 0 ], A[ silk_SMULBB( M, M ) - 1 ] ), SILK_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 ); + for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) { + status = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L_Q16, j, 0, M ); + tmp_32 = 0; + for( i = 0; i < j; i++ ) { + v_Q0[ i ] = silk_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */ + tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */ + } + tmp_32 = silk_SUB32( matrix_ptr( A, j, j, M ), tmp_32 ); + + if( tmp_32 < diag_min_value ) { + tmp_32 = silk_SUB32( silk_SMULBB( loop_count + 1, diag_min_value ), tmp_32 ); + /* Matrix not positive semi-definite, or ill conditioned */ + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) = silk_ADD32( matrix_ptr( A, i, i, M ), tmp_32 ); + } + status = 1; + break; + } + D_Q0[ j ] = tmp_32; /* always < max(Correlation) */ + + /* two-step division */ + one_div_diag_Q36 = silk_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */ + one_div_diag_Q40 = silk_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */ + err = silk_SUB32( (opus_int32)1 << 24, silk_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */ + one_div_diag_Q48 = silk_SMULWW( err, one_div_diag_Q40 ); /* Q48 */ + + /* Save 1/Ds */ + inv_D[ j ].Q36_part = one_div_diag_Q36; + inv_D[ j ].Q48_part = one_div_diag_Q48; + + matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */ + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L_Q16, j + 1, 0, M ); + for( i = j + 1; i < M; i++ ) { + tmp_32 = 0; + for( k = 0; k < j; k++ ) { + tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */ + } + tmp_32 = silk_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */ + + /* tmp_32 / D_Q0[j] : Divide to Q16 */ + matrix_ptr( L_Q16, i, j, M ) = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), + silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + + /* go to next column */ + ptr2 += M; + } + } + } + + silk_assert( status == 0 ); +} + +static OPUS_INLINE void silk_LS_divide_Q16_FIX( + opus_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + opus_int M /* I dimension */ +) +{ + opus_int i; + opus_int32 tmp_32; + opus_int32 one_div_diag_Q36, one_div_diag_Q48; + + for( i = 0; i < M; i++ ) { + one_div_diag_Q36 = inv_D[ i ].Q36_part; + one_div_diag_Q48 = inv_D[ i ].Q48_part; + + tmp_32 = T[ i ]; + T[ i ] = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + } +} + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +static OPUS_INLINE void silk_LS_SolveFirst_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +) +{ + opus_int i, j; + const opus_int32 *ptr32; + opus_int32 tmp_32; + + for( i = 0; i < M; i++ ) { + ptr32 = matrix_adr( L_Q16, i, 0, M ); + tmp_32 = 0; + for( j = 0; j < i; j++ ) { + tmp_32 = silk_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] ); + } + x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 ); + } +} + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +static OPUS_INLINE void silk_LS_SolveLast_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +) +{ + opus_int i, j; + const opus_int32 *ptr32; + opus_int32 tmp_32; + + for( i = M - 1; i >= 0; i-- ) { + ptr32 = matrix_adr( L_Q16, 0, i, M ); + tmp_32 = 0; + for( j = M - 1; j > i; j-- ) { + tmp_32 = silk_SMLAWW( tmp_32, ptr32[ silk_SMULBB( j, M ) ], x_Q16[ j ] ); + } + x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 ); + } +} diff --git a/thirdparty/opus/silk/fixed/structs_FIX.h b/thirdparty/opus/silk/fixed/structs_FIX.h index 2774a97b24..3294b25128 100644 --- a/thirdparty/opus/silk/fixed/structs_FIX.h +++ b/thirdparty/opus/silk/fixed/structs_FIX.h @@ -48,16 +48,30 @@ typedef struct { } silk_shape_state_FIX; /********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + opus_int16 sLTP_shp[ LTP_BUF_LENGTH ]; + opus_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int sLTP_shp_buf_idx; + opus_int32 sLF_AR_shp_Q12; + opus_int32 sLF_MA_shp_Q12; + opus_int32 sHarmHP_Q2; + opus_int32 rand_seed; + opus_int lagPrev; +} silk_prefilter_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 */ + silk_prefilter_state_FIX sPrefilt; /* Prefilter 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; /************************/ @@ -73,8 +87,11 @@ typedef struct { /* Noise shaping parameters */ /* Testing */ - silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_DWORD_ALIGN opus_int16 AR1_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_DWORD_ALIGN opus_int16 AR2_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 GainsPre_Q14[ MAX_NB_SUBFR ]; + opus_int HarmBoost_Q14[ MAX_NB_SUBFR ]; opus_int Tilt_Q14[ MAX_NB_SUBFR ]; opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; opus_int Lambda_Q10; @@ -82,6 +99,7 @@ typedef struct { opus_int coding_quality_Q14; /* measures */ + opus_int sparseness_Q8; opus_int32 predGain_Q16; opus_int LTPredCodGain_Q7; opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ diff --git a/thirdparty/opus/silk/fixed/warped_autocorrelation_FIX.c b/thirdparty/opus/silk/fixed/warped_autocorrelation_FIX.c index 5c79553bc0..6ca6c1184d 100644 --- a/thirdparty/opus/silk/fixed/warped_autocorrelation_FIX.c +++ b/thirdparty/opus/silk/fixed/warped_autocorrelation_FIX.c @@ -31,14 +31,17 @@ POSSIBILITY OF SUCH DAMAGE. #include "main_FIX.h" +#define QC 10 +#define QS 14 + #if defined(MIPSr1_ASM) #include "mips/warped_autocorrelation_FIX_mipsr1.h" #endif +#ifndef OVERRIDE_silk_warped_autocorrelation_FIX /* Autocorrelations for a warped frequency axis */ -#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c -void silk_warped_autocorrelation_FIX_c( +void silk_warped_autocorrelation_FIX( 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 */ @@ -53,7 +56,7 @@ void silk_warped_autocorrelation_FIX_c( opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; /* Order must be even */ - celt_assert( ( order & 1 ) == 0 ); + silk_assert( ( order & 1 ) == 0 ); silk_assert( 2 * QS - QC >= 0 ); /* Loop over samples */ @@ -89,4 +92,4 @@ void silk_warped_autocorrelation_FIX_c( } silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ } -#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ +#endif /* OVERRIDE_silk_warped_autocorrelation_FIX */ diff --git a/thirdparty/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c b/thirdparty/opus/silk/fixed/x86/burg_modified_FIX_sse.c index bbb1ce0fcc..3c3583c5fc 100644 --- a/thirdparty/opus/silk/fixed/x86/burg_modified_FIX_sse4_1.c +++ b/thirdparty/opus/silk/fixed/x86/burg_modified_FIX_sse.c @@ -72,7 +72,7 @@ void silk_burg_modified_sse4_1( __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 ); + silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); /* Compute autocorrelations, added over subframes */ silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); diff --git a/thirdparty/opus/silk/fixed/x86/prefilter_FIX_sse.c b/thirdparty/opus/silk/fixed/x86/prefilter_FIX_sse.c new file mode 100644 index 0000000000..488a603f5d --- /dev/null +++ b/thirdparty/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 <xmmintrin.h> +#include <emmintrin.h> +#include <smmintrin.h> +#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 */ + silk_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; + + silk_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 = (coef_Q13_8 * state_8) >> 16; + sum += (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/thirdparty/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c b/thirdparty/opus/silk/fixed/x86/vector_ops_FIX_sse.c index c1e90564d0..c1e90564d0 100644 --- a/thirdparty/opus/silk/fixed/x86/vector_ops_FIX_sse4_1.c +++ b/thirdparty/opus/silk/fixed/x86/vector_ops_FIX_sse.c diff --git a/thirdparty/opus/silk/float/LPC_analysis_filter_FLP.c b/thirdparty/opus/silk/float/LPC_analysis_filter_FLP.c index 0e1a1fed0f..cae89a0a18 100644 --- a/thirdparty/opus/silk/float/LPC_analysis_filter_FLP.c +++ b/thirdparty/opus/silk/float/LPC_analysis_filter_FLP.c @@ -215,7 +215,7 @@ void silk_LPC_analysis_filter_FLP( const opus_int Order /* I LPC order */ ) { - celt_assert( Order <= length ); + silk_assert( Order <= length ); switch( Order ) { case 6: @@ -239,7 +239,7 @@ void silk_LPC_analysis_filter_FLP( break; default: - celt_assert( 0 ); + silk_assert( 0 ); break; } diff --git a/thirdparty/opus/silk/float/LPC_inv_pred_gain_FLP.c b/thirdparty/opus/silk/float/LPC_inv_pred_gain_FLP.c index 2be2122d61..25178bacdd 100644 --- a/thirdparty/opus/silk/float/LPC_inv_pred_gain_FLP.c +++ b/thirdparty/opus/silk/float/LPC_inv_pred_gain_FLP.c @@ -31,7 +31,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "SigProc_FIX.h" #include "SigProc_FLP.h" -#include "define.h" + +#define RC_THRESHOLD 0.9999f /* compute inverse of LPC prediction gain, and */ /* test if LPC coefficients are stable (all poles within unit circle) */ @@ -42,32 +43,34 @@ silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction ga ) { opus_int k, n; - double invGain, rc, rc_mult1, rc_mult2, tmp1, tmp2; - silk_float Atmp[ SILK_MAX_ORDER_LPC ]; + double invGain, rc, rc_mult1, rc_mult2; + silk_float Atmp[ 2 ][ SILK_MAX_ORDER_LPC ]; + silk_float *Aold, *Anew; - silk_memcpy( Atmp, A, order * sizeof(silk_float) ); + Anew = Atmp[ order & 1 ]; + silk_memcpy( Anew, 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 ) { + rc = -Anew[ k ]; + if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { return 0.0f; } + rc_mult1 = 1.0f - rc * rc; 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 ); + invGain *= rc_mult1; + /* swap pointers */ + Aold = Anew; + Anew = Atmp[ k & 1 ]; + for( n = 0; n < k; n++ ) { + Anew[ n ] = (silk_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 ); } } - rc = -Atmp[ 0 ]; - rc_mult1 = 1.0f - rc * rc; - invGain *= rc_mult1; - if( invGain * MAX_PREDICTION_POWER_GAIN < 1.0f ) { + rc = -Anew[ 0 ]; + if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { return 0.0f; } + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; return (silk_float)invGain; } diff --git a/thirdparty/opus/silk/float/SigProc_FLP.h b/thirdparty/opus/silk/float/SigProc_FLP.h index 953de8b09e..f0cb3733be 100644 --- a/thirdparty/opus/silk/float/SigProc_FLP.h +++ b/thirdparty/opus/silk/float/SigProc_FLP.h @@ -68,6 +68,13 @@ void silk_k2a_FLP( opus_int32 order /* I prediction order */ ); +/* Solve the normal equations using the Levinson-Durbin recursion */ +silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ + silk_float A[], /* O prediction coefficients [order] */ + const silk_float corr[], /* I input auto-correlations [order + 1] */ + const opus_int order /* I prediction order */ +); + /* compute autocorrelation */ void silk_autocorrelation_FLP( silk_float *results, /* O result (length correlationCount) */ diff --git a/thirdparty/opus/silk/float/apply_sine_window_FLP.c b/thirdparty/opus/silk/float/apply_sine_window_FLP.c index e49e717991..6aae57c0ab 100644 --- a/thirdparty/opus/silk/float/apply_sine_window_FLP.c +++ b/thirdparty/opus/silk/float/apply_sine_window_FLP.c @@ -45,10 +45,10 @@ void silk_apply_sine_window_FLP( opus_int k; silk_float freq, c, S0, S1; - celt_assert( win_type == 1 || win_type == 2 ); + silk_assert( win_type == 1 || win_type == 2 ); /* Length must be multiple of 4 */ - celt_assert( ( length & 3 ) == 0 ); + silk_assert( ( length & 3 ) == 0 ); freq = PI / ( length + 1 ); diff --git a/thirdparty/opus/silk/float/burg_modified_FLP.c b/thirdparty/opus/silk/float/burg_modified_FLP.c index 756b76a35b..ea5dc25a93 100644 --- a/thirdparty/opus/silk/float/burg_modified_FLP.c +++ b/thirdparty/opus/silk/float/burg_modified_FLP.c @@ -52,7 +52,7 @@ silk_float silk_burg_modified_FLP( /* O returns residual energy 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 ); + silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); /* Compute autocorrelations, added over subframes */ C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); diff --git a/thirdparty/opus/silk/float/encode_frame_FLP.c b/thirdparty/opus/silk/float/encode_frame_FLP.c index b029c3f5ca..2092a4d9e2 100644 --- a/thirdparty/opus/silk/float/encode_frame_FLP.c +++ b/thirdparty/opus/silk/float/encode_frame_FLP.c @@ -29,7 +29,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "config.h" #endif -#include <stdlib.h> #include "main_FLP.h" #include "tuning_parameters.h" @@ -42,28 +41,21 @@ static OPUS_INLINE void silk_LBRR_encode_FLP( ); 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 */ + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ ) { - 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 ) { + if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; psEnc->sCmn.noSpeechCounter++; - if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + 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; @@ -93,6 +85,7 @@ opus_int silk_encode_frame_FLP( 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 xfw[ MAX_FRAME_LENGTH ]; silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; ec_enc sRangeEnc_copy, sRangeEnc_copy2; silk_nsq_state sNSQ_copy, sNSQ_copy2; @@ -104,9 +97,6 @@ opus_int silk_encode_frame_FLP( 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; @@ -149,17 +139,22 @@ opus_int silk_encode_frame_FLP( /***************************************************/ /* Find linear prediction coefficients (LPC + LTP) */ /***************************************************/ - silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); /****************************************/ /* Process gains */ /****************************************/ silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame ); + /****************************************/ /* Low Bitrate Redundant Encoding */ /****************************************/ - silk_LBRR_encode_FLP( psEnc, &sEncCtrl, x_frame, condCoding ); + silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding ); /* Loop over quantizer and entroy coding to control bitrate */ maxIter = 6; @@ -193,11 +188,7 @@ opus_int silk_encode_frame_FLP( /*****************************************/ /* 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 ) ); - } + silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw ); /****************************************/ /* Encode Parameters */ @@ -212,33 +203,6 @@ opus_int silk_encode_frame_FLP( 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; } @@ -248,7 +212,7 @@ opus_int silk_encode_frame_FLP( 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_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; @@ -259,9 +223,7 @@ opus_int silk_encode_frame_FLP( 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; + sEncCtrl.Lambda *= 1.5f; found_upper = 0; gainsID_upper = -1; } else { @@ -278,7 +240,7 @@ opus_int silk_encode_frame_FLP( gainsID_lower = gainsID; /* Copy part of the output state */ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); - celt_assert( psRangeEnc->offs <= 1275 ); + silk_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; @@ -288,34 +250,15 @@ opus_int silk_encode_frame_FLP( 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 */ + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); 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 ); + gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); } + 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 ); @@ -329,13 +272,7 @@ opus_int silk_encode_frame_FLP( } 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 ); + pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); } /* Quantize gains */ diff --git a/thirdparty/opus/silk/float/energy_FLP.c b/thirdparty/opus/silk/float/energy_FLP.c index 7bc7173c9c..24b8179f9e 100644 --- a/thirdparty/opus/silk/float/energy_FLP.c +++ b/thirdparty/opus/silk/float/energy_FLP.c @@ -37,12 +37,13 @@ double silk_energy_FLP( opus_int dataSize ) { - opus_int i; + opus_int i, dataSize4; double result; /* 4x unrolled loop */ result = 0.0; - for( i = 0; i < dataSize - 3; i += 4 ) { + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { result += data[ i + 0 ] * (double)data[ i + 0 ] + data[ i + 1 ] * (double)data[ i + 1 ] + data[ i + 2 ] * (double)data[ i + 2 ] + diff --git a/thirdparty/opus/silk/float/find_LPC_FLP.c b/thirdparty/opus/silk/float/find_LPC_FLP.c index fa3ffe7f8b..fcfe1c3681 100644 --- a/thirdparty/opus/silk/float/find_LPC_FLP.c +++ b/thirdparty/opus/silk/float/find_LPC_FLP.c @@ -73,7 +73,7 @@ void silk_find_LPC_FLP( 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 ); + silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder ); /* Calculate residual energy with LSF interpolation */ silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); @@ -99,6 +99,6 @@ void silk_find_LPC_FLP( silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); } - celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || + silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); } diff --git a/thirdparty/opus/silk/float/find_LTP_FLP.c b/thirdparty/opus/silk/float/find_LTP_FLP.c index f97064930e..7229996014 100644 --- a/thirdparty/opus/silk/float/find_LTP_FLP.c +++ b/thirdparty/opus/silk/float/find_LTP_FLP.c @@ -33,32 +33,100 @@ POSSIBILITY OF SUCH DAMAGE. #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 */ + silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float *LTPredCodGain, /* O LTP coding gain */ + const silk_float r_lpc[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ const opus_int subfr_length, /* I Subframe length */ - const opus_int nb_subfr /* I number of subframes */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset /* I Number of samples in LTP memory */ ) { - opus_int k; - silk_float *xX_ptr, *XX_ptr; - const silk_float *lag_ptr; - silk_float xx, temp; + opus_int i, k; + silk_float *b_ptr, temp, *WLTP_ptr; + silk_float LPC_res_nrg, LPC_LTP_res_nrg; + silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ]; + silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu; + silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; + const silk_float *r_ptr, *lag_ptr; - xX_ptr = xX; - XX_ptr = XX; + b_ptr = b; + WLTP_ptr = WLTP; + r_ptr = &r_lpc[ mem_offset ]; 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; + silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr ); + silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr ); + + rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length ); + regu = 1.0f + rr[ k ] + + matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) + + matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ); + regu *= LTP_DAMPING / 3; + silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER ); + silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER ); + + temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); + silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER ); + w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER ); + + r_ptr += subfr_length; + b_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Compute LTP coding gain */ + if( LTPredCodGain != NULL ) { + LPC_LTP_res_nrg = 1e-6f; + LPC_res_nrg = 0.0f; + for( k = 0; k < nb_subfr; k++ ) { + LPC_res_nrg += rr[ k ] * Wght[ k ]; + LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ]; + } + + silk_assert( LPC_LTP_res_nrg > 0 ); + *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg ); + } + + /* Smoothing */ + /* d = sum( B, 1 ); */ + b_ptr = b; + for( k = 0; k < nb_subfr; k++ ) { + d[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d[ k ] += b_ptr[ i ]; + } + b_ptr += LTP_ORDER; + } + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + temp = 1e-3f; + for( k = 0; k < nb_subfr; k++ ) { + temp += w[ k ]; + } + m = 0; + for( k = 0; k < nb_subfr; k++ ) { + m += d[ k ] * w[ k ]; + } + m = m / temp; + + b_ptr = b; + for( k = 0; k < nb_subfr; k++ ) { + g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] ); + temp = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f ); + temp += delta_b[ i ]; + } + temp = g / temp; + for( i = 0; i < LTP_ORDER; i++ ) { + b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp; + } + b_ptr += LTP_ORDER; } } diff --git a/thirdparty/opus/silk/float/find_pitch_lags_FLP.c b/thirdparty/opus/silk/float/find_pitch_lags_FLP.c index dedbcd2836..f3b22d25ce 100644 --- a/thirdparty/opus/silk/float/find_pitch_lags_FLP.c +++ b/thirdparty/opus/silk/float/find_pitch_lags_FLP.c @@ -56,7 +56,7 @@ void silk_find_pitch_lags_FLP( 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 ); + silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); x_buf = x - psEnc->sCmn.ltp_mem_length; diff --git a/thirdparty/opus/silk/float/find_pred_coefs_FLP.c b/thirdparty/opus/silk/float/find_pred_coefs_FLP.c index dcf7c5202d..1af4fe5f1b 100644 --- a/thirdparty/opus/silk/float/find_pred_coefs_FLP.c +++ b/thirdparty/opus/silk/float/find_pred_coefs_FLP.c @@ -41,9 +41,8 @@ void silk_find_pred_coefs_FLP( ) { 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 ]; + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + silk_float invGains[ MAX_NB_SUBFR ], Wght[ 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 ]; @@ -53,20 +52,23 @@ void silk_find_pred_coefs_FLP( for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { silk_assert( psEncCtrl->Gains[ i ] > 0.0f ); invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + Wght[ i ] = invGains[ i ] * invGains[ 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 ); + silk_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 ); + silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch, + psEncCtrl->pitchL, Wght, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length ); /* 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 ); + &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr, + psEnc->sCmn.arch ); /* Control LTP scaling */ silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding ); diff --git a/thirdparty/opus/silk/float/inner_product_FLP.c b/thirdparty/opus/silk/float/inner_product_FLP.c index cdd39d24ce..029c012911 100644 --- a/thirdparty/opus/silk/float/inner_product_FLP.c +++ b/thirdparty/opus/silk/float/inner_product_FLP.c @@ -38,12 +38,13 @@ double silk_inner_product_FLP( opus_int dataSize ) { - opus_int i; + opus_int i, dataSize4; double result; /* 4x unrolled loop */ result = 0.0; - for( i = 0; i < dataSize - 3; i += 4 ) { + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { result += data1[ i + 0 ] * (double)data2[ i + 0 ] + data1[ i + 1 ] * (double)data2[ i + 1 ] + data1[ i + 2 ] * (double)data2[ i + 2 ] + diff --git a/thirdparty/opus/silk/float/k2a_FLP.c b/thirdparty/opus/silk/float/k2a_FLP.c index 1448008dbb..12af4e7669 100644 --- a/thirdparty/opus/silk/float/k2a_FLP.c +++ b/thirdparty/opus/silk/float/k2a_FLP.c @@ -39,16 +39,15 @@ void silk_k2a_FLP( ) { opus_int k, n; - silk_float rck, tmp1, tmp2; + silk_float Atmp[ SILK_MAX_ORDER_LPC ]; 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; + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A[ n ]; } - A[ k ] = -rck; + for( n = 0; n < k; n++ ) { + A[ n ] += Atmp[ k - n - 1 ] * rc[ k ]; + } + A[ k ] = -rc[ k ]; } } diff --git a/thirdparty/opus/silk/float/levinsondurbin_FLP.c b/thirdparty/opus/silk/float/levinsondurbin_FLP.c new file mode 100644 index 0000000000..f0ba606981 --- /dev/null +++ b/thirdparty/opus/silk/float/levinsondurbin_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 "SigProc_FLP.h" + +/* Solve the normal equations using the Levinson-Durbin recursion */ +silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ + silk_float A[], /* O prediction coefficients [order] */ + const silk_float corr[], /* I input auto-correlations [order + 1] */ + const opus_int order /* I prediction order */ +) +{ + opus_int i, mHalf, m; + silk_float min_nrg, nrg, t, km, Atmp1, Atmp2; + + min_nrg = 1e-12f * corr[ 0 ] + 1e-9f; + nrg = corr[ 0 ]; + nrg = silk_max_float(min_nrg, nrg); + A[ 0 ] = corr[ 1 ] / nrg; + nrg -= A[ 0 ] * corr[ 1 ]; + nrg = silk_max_float(min_nrg, nrg); + + for( m = 1; m < order; m++ ) + { + t = corr[ m + 1 ]; + for( i = 0; i < m; i++ ) { + t -= A[ i ] * corr[ m - i ]; + } + + /* reflection coefficient */ + km = t / nrg; + + /* residual energy */ + nrg -= km * t; + nrg = silk_max_float(min_nrg, nrg); + + mHalf = m >> 1; + for( i = 0; i < mHalf; i++ ) { + Atmp1 = A[ i ]; + Atmp2 = A[ m - i - 1 ]; + A[ m - i - 1 ] -= km * Atmp1; + A[ i ] -= km * Atmp2; + } + if( m & 1 ) { + A[ mHalf ] -= km * A[ mHalf ]; + } + A[ m ] = km; + } + + /* return the residual energy */ + return nrg; +} + diff --git a/thirdparty/opus/silk/float/main_FLP.h b/thirdparty/opus/silk/float/main_FLP.h index 5dc0ccf4a4..e5a75972e5 100644 --- a/thirdparty/opus/silk/float/main_FLP.h +++ b/thirdparty/opus/silk/float/main_FLP.h @@ -56,8 +56,7 @@ void silk_HP_variable_cutoff( /* 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 */ + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ ); /* Encoder main function */ @@ -80,11 +79,22 @@ opus_int silk_init_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_int32 TargetRate_bps, /* I Target max bitrate (bps) */ 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 ); +/****************/ +/* Prefiltering */ +/****************/ +void silk_prefilter_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + silk_float xw[], /* O Weighted signal */ + const silk_float x[] /* I Speech signal */ +); + /**************************/ /* Noise shaping analysis */ /**************************/ @@ -143,12 +153,15 @@ void silk_find_LPC_FLP( /* 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 */ + silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float *LTPredCodGain, /* O LTP coding gain */ + const silk_float r_lpc[], /* I LPC residual */ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ const opus_int subfr_length, /* I Subframe length */ - const opus_int nb_subfr /* I number of subframes */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset /* I Number of samples in LTP memory */ ); void silk_LTP_analysis_filter_FLP( @@ -185,15 +198,14 @@ void silk_LPC_analysis_filter_FLP( /* LTP tap quantizer */ void silk_quant_LTP_gains_FLP( - silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)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 */ + const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */ + const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */ + const opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr, /* I number of subframes */ int arch /* I Run-time architecture */ ); @@ -233,6 +245,22 @@ void silk_corrVector_FLP( silk_float *Xt /* O X'*t correlation vector [order] */ ); +/* 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 */ +); + +/* Function to solve linear equation Ax = b, where A is an MxM symmetric matrix */ +void silk_solve_LDL_FLP( + silk_float *A, /* I/O Symmetric square matrix, out: reg. */ + const opus_int M, /* I Size of matrix */ + const silk_float *b, /* I Pointer to b vector */ + silk_float *x /* O Pointer to x solution vector */ +); + /* Apply sine window to signal vector. */ /* Window types: */ /* 1 -> sine window from 0 to pi/2 */ @@ -257,8 +285,7 @@ void silk_A2NLSF_FLP( 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 */ + const opus_int LPC_order /* I LPC order */ ); /* Limit, stabilize, and quantize NLSFs */ diff --git a/thirdparty/opus/silk/float/noise_shape_analysis_FLP.c b/thirdparty/opus/silk/float/noise_shape_analysis_FLP.c index cb3d8a50b7..65f6ea5870 100644 --- a/thirdparty/opus/silk/float/noise_shape_analysis_FLP.c +++ b/thirdparty/opus/silk/float/noise_shape_analysis_FLP.c @@ -55,21 +55,25 @@ static OPUS_INLINE silk_float warped_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 *coefs_syn, + silk_float *coefs_ana, silk_float lambda, silk_float limit, opus_int order ) { opus_int i, iter, ind = 0; - silk_float tmp, maxabs, chirp, gain; + silk_float tmp, maxabs, chirp, gain_syn, gain_ana; /* Convert to monic coefficients */ for( i = order - 1; i > 0; i-- ) { - coefs[ i - 1 ] -= lambda * coefs[ i ]; + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; } - gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); for( i = 0; i < order; i++ ) { - coefs[ i ] *= gain; + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; } /* Limit */ @@ -77,7 +81,7 @@ static OPUS_INLINE void warped_true2monic_coefs( /* Find maximum absolute value */ maxabs = -1.0f; for( i = 0; i < order; i++ ) { - tmp = silk_abs_float( coefs[ i ] ); + tmp = silk_max( silk_abs_float( coefs_syn[ i ] ), silk_abs_float( coefs_ana[ i ] ) ); if( tmp > maxabs ) { maxabs = tmp; ind = i; @@ -90,59 +94,36 @@ static OPUS_INLINE void warped_true2monic_coefs( /* Convert back to true warped coefficients */ for( i = 1; i < order; i++ ) { - coefs[ i - 1 ] += lambda * coefs[ i ]; + coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ]; } - gain = 1.0f / gain; + gain_syn = 1.0f / gain_syn; + gain_ana = 1.0f / gain_ana; for( i = 0; i < order; i++ ) { - coefs[ i ] *= gain; + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; } /* Apply bandwidth expansion */ chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); - silk_bwexpander_FLP( coefs, order, chirp ); + silk_bwexpander_FLP( coefs_syn, order, chirp ); + silk_bwexpander_FLP( coefs_ana, order, chirp ); /* Convert to monic warped coefficients */ for( i = order - 1; i > 0; i-- ) { - coefs[ i - 1 ] -= lambda * coefs[ i ]; + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; } - gain = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs[ 0 ] ); + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); for( i = 0; i < order; i++ ) { - coefs[ i ] *= gain; + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; } } 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 */ @@ -152,13 +133,12 @@ void silk_noise_shape_analysis_FLP( ) { 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; + opus_int k, nSamples; + silk_float SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt; + silk_float nrg, pre_nrg, log_energy, log_energy_prev, energy_variation; + silk_float delta, BWExp1, BWExp2, 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 */ @@ -196,14 +176,14 @@ void silk_noise_shape_analysis_FLP( if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { /* Initially set to 0; may be overruled in process_gains(..) */ psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness = 0.0f; } 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++ ) { + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples ); log_energy = silk_log2( nrg ); if( k > 0 ) { @@ -212,13 +192,17 @@ void silk_noise_shape_analysis_FLP( log_energy_prev = log_energy; pitch_res_ptr += nSamples; } + psEncCtrl->sparseness = silk_sigmoid( 0.4f * ( energy_variation - 5.0f ) ); /* Set quantization offset depending on sparseness measure */ - if( energy_variation > ENERGY_VARIATION_THRESHOLD_QNT_OFFSET * (nSegs-1) ) { + if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) { psEnc->sCmn.indices.quantOffsetType = 0; } else { psEnc->sCmn.indices.quantOffsetType = 1; } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f ); } /*******************************/ @@ -226,10 +210,19 @@ void silk_noise_shape_analysis_FLP( /*******************************/ /* 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; + BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + delta = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality ); + BWExp1 -= delta; + BWExp2 += delta; + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1 /= BWExp2; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* 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; + } else { + warping = 0.0f; + } /********************************************/ /* Compute noise shaping AR coefs and gains */ @@ -259,28 +252,37 @@ void silk_noise_shape_analysis_FLP( } /* Add white noise, as a fraction of energy */ - auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION + 1.0f; + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION; /* 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 ); + nrg = silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, 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 ); + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ 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 ); + silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 ); - 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 ); - } + /* Compute noise shaping filter coefficients */ + silk_memcpy( + &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], + psEnc->sCmn.shapingLPCOrder * sizeof( silk_float ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); } /*****************/ @@ -294,6 +296,11 @@ void silk_noise_shape_analysis_FLP( psEncCtrl->Gains[ k ] += gain_add; } + gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre[ k ] *= gain_mult; + } + /************************************************/ /* Control low-frequency shaping and noise tilt */ /************************************************/ @@ -324,6 +331,12 @@ void silk_noise_shape_analysis_FLP( /****************************/ /* HARMONIC SHAPING CONTROL */ /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr; + + /* More harmonic boost for noisy input signals */ + HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality ); + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { /* Harmonic noise shaping */ HarmShapeGain = HARMONIC_SHAPING; @@ -342,6 +355,8 @@ void silk_noise_shape_analysis_FLP( /* Smooth over subframes */ /*************************/ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psShapeSt->HarmBoost_smth += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth ); + psEncCtrl->HarmBoost[ k ] = psShapeSt->HarmBoost_smth; 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 ); diff --git a/thirdparty/opus/silk/float/pitch_analysis_core_FLP.c b/thirdparty/opus/silk/float/pitch_analysis_core_FLP.c index f351bc3718..d0e637a29d 100644 --- a/thirdparty/opus/silk/float/pitch_analysis_core_FLP.c +++ b/thirdparty/opus/silk/float/pitch_analysis_core_FLP.c @@ -109,11 +109,11 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, const opus_int8 *Lag_CB_ptr; /* Check for valid sampling frequency */ - celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + silk_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( complexity >= SILK_PE_MIN_COMPLEX ); + silk_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 ); @@ -148,7 +148,7 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 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_assert( Fs_kHz == 8 ); silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz ); } @@ -159,7 +159,7 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, /* 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 ] ); + frame_4kHz[ i ] += frame_4kHz[ i - 1 ]; } /****************************************************************************** @@ -169,14 +169,14 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 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 ); + silk_assert( target_ptr >= frame_4kHz ); + silk_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 ); + silk_assert( basis_ptr >= frame_4kHz ); + silk_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 ); @@ -215,7 +215,7 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, /* Sort */ length_d_srch = 4 + 2 * complexity; - celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_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 */ @@ -238,7 +238,7 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, break; } } - celt_assert( length_d_srch > 0 ); + silk_assert( length_d_srch > 0 ); for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { d_comp[ i ] = 0; @@ -471,7 +471,7 @@ opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, *lagIndex = (opus_int16)( lag - min_lag_8kHz ); *contourIndex = (opus_int8)CBimax; } - celt_assert( *lagIndex >= 0 ); + silk_assert( *lagIndex >= 0 ); /* return as voiced */ return 0; } @@ -506,8 +506,8 @@ static void silk_P_Ana_calc_corr_st3( 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 ); + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); if( nb_subfr == PE_MAX_NB_SUBFR ) { Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; @@ -515,7 +515,7 @@ static void silk_P_Ana_calc_corr_st3( 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); + silk_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; @@ -572,8 +572,8 @@ static void silk_P_Ana_calc_energy_st3( 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 ); + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); if( nb_subfr == PE_MAX_NB_SUBFR ) { Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; @@ -581,7 +581,7 @@ static void silk_P_Ana_calc_energy_st3( 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); + silk_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; diff --git a/thirdparty/opus/silk/float/prefilter_FLP.c b/thirdparty/opus/silk/float/prefilter_FLP.c new file mode 100644 index 0000000000..8bc32fb410 --- /dev/null +++ b/thirdparty/opus/silk/float/prefilter_FLP.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_FLP.h" +#include "tuning_parameters.h" + +/* +* Prefilter for finding Quantizer input signal +*/ +static OPUS_INLINE void silk_prefilt_FLP( + silk_prefilter_state_FLP *P, /* I/O state */ + silk_float st_res[], /* I */ + silk_float xw[], /* O */ + silk_float *HarmShapeFIR, /* I */ + silk_float Tilt, /* I */ + silk_float LF_MA_shp, /* I */ + silk_float LF_AR_shp, /* I */ + opus_int lag, /* I */ + opus_int length /* I */ +); + +static void silk_warped_LPC_analysis_filter_FLP( + silk_float state[], /* I/O State [order + 1] */ + silk_float res[], /* O Residual signal [length] */ + const silk_float coef[], /* I Coefficients [order] */ + const silk_float input[], /* I Input signal [length] */ + const silk_float lambda, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + silk_float acc, tmp1, tmp2; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = state[ 0 ] + lambda * state[ 1 ]; + state[ 0 ] = input[ n ]; + /* Output of allpass section */ + tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 ); + state[ 1 ] = tmp2; + acc = coef[ 0 ] * tmp2; + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + acc += coef[ i - 1 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + acc += coef[ i ] * tmp2; + } + state[ order ] = tmp1; + acc += coef[ order - 1 ] * tmp1; + res[ n ] = input[ n ] - acc; + } +} + +/* +* silk_prefilter. Main prefilter function +*/ +void silk_prefilter_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + silk_float xw[], /* O Weighted signal */ + const silk_float x[] /* I Speech signal */ +) +{ + silk_prefilter_state_FLP *P = &psEnc->sPrefilt; + opus_int j, k, lag; + silk_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp; + silk_float B[ 2 ]; + const silk_float *AR1_shp; + const silk_float *px; + silk_float *pxw; + silk_float HarmShapeFIR[ 3 ]; + silk_float st_res[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ]; + + /* Set up pointers */ + px = x; + pxw = xw; + lag = P->lagPrev; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Update Variables that change per sub frame */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + lag = psEncCtrl->pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] ); + HarmShapeFIR[ 0 ] = 0.25f * HarmShapeGain; + HarmShapeFIR[ 1 ] = 32767.0f / 65536.0f * HarmShapeGain; + HarmShapeFIR[ 2 ] = 0.25f * HarmShapeGain; + Tilt = psEncCtrl->Tilt[ k ]; + LF_MA_shp = psEncCtrl->LF_MA_shp[ k ]; + LF_AR_shp = psEncCtrl->LF_AR_shp[ k ]; + AR1_shp = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering */ + silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px, + (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B[ 0 ] = psEncCtrl->GainsPre[ k ]; + B[ 1 ] = -psEncCtrl->GainsPre[ k ] * + ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT ); + pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP; + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ]; + } + P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ]; + + silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw += psEnc->sCmn.subfr_length; + } + P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; +} + +/* +* Prefilter for finding Quantizer input signal +*/ +static OPUS_INLINE void silk_prefilt_FLP( + silk_prefilter_state_FLP *P, /* I/O state */ + silk_float st_res[], /* I */ + silk_float xw[], /* O */ + silk_float *HarmShapeFIR, /* I */ + silk_float Tilt, /* I */ + silk_float LF_MA_shp, /* I */ + silk_float LF_AR_shp, /* I */ + opus_int lag, /* I */ + opus_int length /* I */ +) +{ + opus_int i; + opus_int idx, LTP_shp_buf_idx; + silk_float n_Tilt, n_LF, n_LTP; + silk_float sLF_AR_shp, sLF_MA_shp; + silk_float *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 = P->sLF_AR_shp; + sLF_MA_shp = P->sLF_MA_shp; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ] * HarmShapeFIR[ 1 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ]; + } else { + n_LTP = 0; + } + + n_Tilt = sLF_AR_shp * Tilt; + n_LF = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp; + + sLF_AR_shp = st_res[ i ] - n_Tilt; + sLF_MA_shp = sLF_AR_shp - n_LF; + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp; + + xw[ i ] = sLF_MA_shp - n_LTP; + } + /* Copy temp variable back to state */ + P->sLF_AR_shp = sLF_AR_shp; + P->sLF_MA_shp = sLF_MA_shp; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/thirdparty/opus/silk/float/residual_energy_FLP.c b/thirdparty/opus/silk/float/residual_energy_FLP.c index 1bd07b33a4..b2e03a86a4 100644 --- a/thirdparty/opus/silk/float/residual_energy_FLP.c +++ b/thirdparty/opus/silk/float/residual_energy_FLP.c @@ -47,7 +47,7 @@ silk_float silk_residual_energy_covar_FLP( /* O silk_float tmp, nrg = 0.0f, regularization; /* Safety checks */ - celt_assert( D >= 0 ); + silk_assert( D >= 0 ); regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { diff --git a/thirdparty/opus/silk/float/schur_FLP.c b/thirdparty/opus/silk/float/schur_FLP.c index 8526c748d3..ee436f8351 100644 --- a/thirdparty/opus/silk/float/schur_FLP.c +++ b/thirdparty/opus/silk/float/schur_FLP.c @@ -38,23 +38,22 @@ silk_float silk_schur_FLP( /* O returns residual energy ) { opus_int k, n; - double C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; - double Ctmp1, Ctmp2, rc_tmp; + silk_float C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + silk_float Ctmp1, Ctmp2, rc_tmp; - celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC ); + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); /* Copy correlations */ - k = 0; - do { + for( k = 0; k < order+1; k++ ) { 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; + refl_coef[ k ] = rc_tmp; /* Update correlations */ for( n = 0; n < order - k; n++ ) { @@ -66,5 +65,6 @@ silk_float silk_schur_FLP( /* O returns residual energy } /* Return residual energy */ - return (silk_float)C[ 0 ][ 1 ]; + return C[ 0 ][ 1 ]; } + diff --git a/thirdparty/opus/silk/float/solve_LS_FLP.c b/thirdparty/opus/silk/float/solve_LS_FLP.c new file mode 100644 index 0000000000..7c90d665a0 --- /dev/null +++ b/thirdparty/opus/silk/float/solve_LS_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" +#include "tuning_parameters.h" + +/********************************************************************** + * LDL Factorisation. Finds the upper triangular matrix L and the diagonal + * Matrix D (only the diagonal elements returned in a vector)such that + * the symmetric matric A is given by A = L*D*L'. + **********************************************************************/ +static OPUS_INLINE void silk_LDL_FLP( + silk_float *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */ + silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM lower + * triangular matrix, with ones on the diagonal. + **********************************************************************/ +static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +); + +/********************************************************************** + * Function to solve linear equation (A^T)x = b, when A is a MxM lower + * triangular, with ones on the diagonal. (ie then A^T is upper triangular) + **********************************************************************/ +static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM + * symmetric square matrix - using LDL factorisation + **********************************************************************/ +void silk_solve_LDL_FLP( + silk_float *A, /* I/O Symmetric square matrix, out: reg. */ + const opus_int M, /* I Size of matrix */ + const silk_float *b, /* I Pointer to b vector */ + silk_float *x /* O Pointer to x solution vector */ +) +{ + opus_int i; + silk_float L[ MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ]; + silk_float T[ MAX_MATRIX_SIZE ]; + silk_float Dinv[ MAX_MATRIX_SIZE ]; /* inverse diagonal elements of D*/ + + silk_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*(L^T), + where L is lower triangular with ones on diagonal + ****************************************************/ + silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv ); + + /**************************************************** + * substitute D*(L^T) = T. ie: + L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b + ******************************************************/ + silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T ); + + /**************************************************** + D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + for( i = 0; i < M; i++ ) { + T[ i ] = T[ i ] * Dinv[ i ]; + } + /**************************************************** + x = inv(L') * inv(D) * T + *****************************************************/ + silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x ); +} + +static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +) +{ + opus_int i, j; + silk_float temp; + const silk_float *ptr1; + + for( i = M - 1; i >= 0; i-- ) { + ptr1 = matrix_adr( L, 0, i, M ); + temp = 0; + for( j = M - 1; j > i ; j-- ) { + temp += ptr1[ j * M ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +) +{ + opus_int i, j; + silk_float temp; + const silk_float *ptr1; + + for( i = 0; i < M; i++ ) { + ptr1 = matrix_adr( L, i, 0, M ); + temp = 0; + for( j = 0; j < i; j++ ) { + temp += ptr1[ j ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +static OPUS_INLINE void silk_LDL_FLP( + silk_float *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */ + silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */ +) +{ + opus_int i, j, k, loop_count, err = 1; + silk_float *ptr1, *ptr2; + double temp, diag_min_value; + silk_float v[ MAX_MATRIX_SIZE ], D[ MAX_MATRIX_SIZE ]; /* temp arrays*/ + + silk_assert( M <= MAX_MATRIX_SIZE ); + + diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] ); + for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) { + err = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L, j, 0, M ); + temp = matrix_ptr( A, j, j, M ); /* element in row j column j*/ + for( i = 0; i < j; i++ ) { + v[ i ] = ptr1[ i ] * D[ i ]; + temp -= ptr1[ i ] * v[ i ]; + } + if( temp < diag_min_value ) { + /* Badly conditioned matrix: add white noise and run again */ + temp = ( loop_count + 1 ) * diag_min_value - temp; + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) += ( silk_float )temp; + } + err = 1; + break; + } + D[ j ] = ( silk_float )temp; + Dinv[ j ] = ( silk_float )( 1.0f / temp ); + matrix_ptr( L, j, j, M ) = 1.0f; + + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L, j + 1, 0, M); + for( i = j + 1; i < M; i++ ) { + temp = 0.0; + for( k = 0; k < j; k++ ) { + temp += ptr2[ k ] * v[ k ]; + } + matrix_ptr( L, i, j, M ) = ( silk_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] ); + ptr2 += M; /* go to next column*/ + } + } + } + silk_assert( err == 0 ); +} + diff --git a/thirdparty/opus/silk/float/sort_FLP.c b/thirdparty/opus/silk/float/sort_FLP.c index 0e18f31950..f08d7592c5 100644 --- a/thirdparty/opus/silk/float/sort_FLP.c +++ b/thirdparty/opus/silk/float/sort_FLP.c @@ -47,9 +47,9 @@ void silk_insertion_sort_decreasing_FLP( opus_int i, j; /* Safety checks */ - celt_assert( K > 0 ); - celt_assert( L > 0 ); - celt_assert( L >= K ); + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); /* Write start indices in index vector */ for( i = 0; i < K; i++ ) { diff --git a/thirdparty/opus/silk/float/structs_FLP.h b/thirdparty/opus/silk/float/structs_FLP.h index 3150b386e4..14d647ced2 100644 --- a/thirdparty/opus/silk/float/structs_FLP.h +++ b/thirdparty/opus/silk/float/structs_FLP.h @@ -42,16 +42,32 @@ extern "C" /********************************/ typedef struct { opus_int8 LastGainIndex; + silk_float HarmBoost_smth; silk_float HarmShapeGain_smth; silk_float Tilt_smth; } silk_shape_state_FLP; /********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + silk_float sLTP_shp[ LTP_BUF_LENGTH ]; + silk_float sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int sLTP_shp_buf_idx; + silk_float sLF_AR_shp; + silk_float sLF_MA_shp; + silk_float sHarmHP; + opus_int32 rand_seed; + opus_int lagPrev; +} silk_prefilter_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 */ + silk_prefilter_state_FLP sPrefilt; /* Prefilter 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 */ @@ -70,9 +86,12 @@ typedef struct { opus_int pitchL[ MAX_NB_SUBFR ]; /* Noise shaping parameters */ - silk_float AR[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float AR1[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float AR2[ 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 GainsPre[ MAX_NB_SUBFR ]; + silk_float HarmBoost[ MAX_NB_SUBFR ]; silk_float Tilt[ MAX_NB_SUBFR ]; silk_float HarmShapeGain[ MAX_NB_SUBFR ]; silk_float Lambda; @@ -80,6 +99,7 @@ typedef struct { silk_float coding_quality; /* Measures */ + silk_float sparseness; silk_float predGain; silk_float LTPredCodGain; silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ diff --git a/thirdparty/opus/silk/float/warped_autocorrelation_FLP.c b/thirdparty/opus/silk/float/warped_autocorrelation_FLP.c index 09186e73d4..542414f48e 100644 --- a/thirdparty/opus/silk/float/warped_autocorrelation_FLP.c +++ b/thirdparty/opus/silk/float/warped_autocorrelation_FLP.c @@ -42,11 +42,11 @@ void silk_warped_autocorrelation_FLP( { opus_int n, i; double tmp1, tmp2; - double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; - double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; /* Order must be even */ - celt_assert( ( order & 1 ) == 0 ); + silk_assert( ( order & 1 ) == 0 ); /* Loop over samples */ for( n = 0; n < length; n++ ) { diff --git a/thirdparty/opus/silk/float/wrappers_FLP.c b/thirdparty/opus/silk/float/wrappers_FLP.c index ad90b874a4..6666b8efaa 100644 --- a/thirdparty/opus/silk/float/wrappers_FLP.c +++ b/thirdparty/opus/silk/float/wrappers_FLP.c @@ -54,14 +54,13 @@ void silk_A2NLSF_FLP( 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 */ + const opus_int LPC_order /* I LPC order */ ) { opus_int i; opus_int16 a_fix_Q12[ MAX_LPC_ORDER ]; - silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order, arch ); + silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order ); for( i = 0; i < LPC_order; i++ ) { pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f ); @@ -103,14 +102,14 @@ void silk_NSQ_wrapper_FLP( ) { opus_int i, j; - opus_int16 x16[ MAX_FRAME_LENGTH ]; + opus_int32 x_Q3[ 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_int16 AR2_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 ]; @@ -120,7 +119,7 @@ void silk_NSQ_wrapper_FLP( /* 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 ); + AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); } } @@ -156,16 +155,16 @@ void silk_NSQ_wrapper_FLP( /* Convert input to fix */ for( i = 0; i < psEnc->sCmn.frame_length; i++ ) { - x16[ i ] = silk_float2int( x[ i ] ); + x_Q3[ i ] = silk_float2int( 8.0f * 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 ); + silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR2_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 ); + silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14, psEnc->sCmn.arch ); } } @@ -173,35 +172,31 @@ void silk_NSQ_wrapper_FLP( /* Floating-point Silk LTP quantiation wrapper */ /***********************************************/ void silk_quant_LTP_gains_FLP( - silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)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 */ + const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */ + const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */ + const opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr, /* I number of subframes */ int arch /* I Run-time architecture */ ) { - opus_int i, pred_gain_dB_Q7; + opus_int i; 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 ]; + opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*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 ); + B_Q14[ i ] = (opus_int16)silk_float2int( B[ i ] * 16384.0f ); + } + for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) { + W_Q18[ i ] = (opus_int32)silk_float2int( W[ i ] * 262144.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 ); + silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, W_Q18, mu_Q10, lowComplexity, 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/thirdparty/opus/silk/gain_quant.c b/thirdparty/opus/silk/gain_quant.c index ee65245aa3..64ccd0611b 100644 --- a/thirdparty/opus/silk/gain_quant.c +++ b/thirdparty/opus/silk/gain_quant.c @@ -76,7 +76,6 @@ void silk_gains_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 ]; } diff --git a/thirdparty/opus/silk/init_decoder.c b/thirdparty/opus/silk/init_decoder.c index 16c03dcd1c..f887c67886 100644 --- a/thirdparty/opus/silk/init_decoder.c +++ b/thirdparty/opus/silk/init_decoder.c @@ -44,7 +44,6 @@ opus_int silk_init_decoder( /* 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 ); diff --git a/thirdparty/opus/silk/interpolate.c b/thirdparty/opus/silk/interpolate.c index 833c28ef8e..1bd8ca4d53 100644 --- a/thirdparty/opus/silk/interpolate.c +++ b/thirdparty/opus/silk/interpolate.c @@ -42,8 +42,8 @@ void silk_interpolate( { opus_int i; - celt_assert( ifact_Q2 >= 0 ); - celt_assert( ifact_Q2 <= 4 ); + silk_assert( ifact_Q2 >= 0 ); + silk_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/thirdparty/opus/silk/lin2log.c b/thirdparty/opus/silk/lin2log.c index 0d5155aa86..d4fe515321 100644 --- a/thirdparty/opus/silk/lin2log.c +++ b/thirdparty/opus/silk/lin2log.c @@ -41,6 +41,6 @@ opus_int32 silk_lin2log( 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 ); + return silk_LSHIFT( 31 - lz, 7 ) + silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ); } diff --git a/thirdparty/opus/silk/macros.h b/thirdparty/opus/silk/macros.h index 3c67b6e5d9..d3ca347520 100644 --- a/thirdparty/opus/silk/macros.h +++ b/thirdparty/opus/silk/macros.h @@ -36,6 +36,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "opus_defines.h" #include "arch.h" +#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 + /* This is an OPUS_INLINE header file for general platform. */ /* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ diff --git a/thirdparty/opus/silk/main.h b/thirdparty/opus/silk/main.h index 1a33eed549..2f90d68f7d 100644 --- a/thirdparty/opus/silk/main.h +++ b/thirdparty/opus/silk/main.h @@ -42,10 +42,6 @@ POSSIBILITY OF SUCH DAMAGE. #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 */ @@ -113,22 +109,22 @@ void silk_stereo_decode_mid_only( /* 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 */ + 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 */ + 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 */ @@ -209,37 +205,37 @@ void silk_interpolate( /* LTP tap quantizer */ void silk_quant_LTP_gains( - opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)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 */ + const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ + opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ + opus_int lowComplexity, /* I Flag for low complexity */ + 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_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ 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_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 subfr_len, /* I number of samples per subframe */ + 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 */ - const opus_int L /* I number of vectors in codebook */ + 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)) +#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_c(ind, rate_dist_Q14, gain_Q7, in_Q14, W_Q18, cb_Q7, cb_gain_Q7, cl_Q5, \ + mu_Q9, max_gain_Q7, L)) #endif /************************************/ @@ -247,14 +243,14 @@ void silk_VQ_WMat_EC_c( /************************************/ void silk_NSQ_c( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O Encoder State */ silk_nsq_state *NSQ, /* I/O NSQ state */ SideInfoIndices *psIndices, /* I/O Quantization Indices */ - const opus_int16 x16[], /* I Input */ + 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 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping 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 */ @@ -265,22 +261,22 @@ void silk_NSQ_c( ); #if !defined(OVERRIDE_silk_NSQ) -#define silk_NSQ(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ +#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_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + ((void)(arch),silk_NSQ_c(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 /* Noise shaping using delayed decision */ void silk_NSQ_del_dec_c( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O Encoder State */ silk_nsq_state *NSQ, /* I/O NSQ state */ SideInfoIndices *psIndices, /* I/O Quantization Indices */ - const opus_int16 x16[], /* I Input */ + 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 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping 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 */ @@ -291,9 +287,9 @@ void silk_NSQ_del_dec_c( ); #if !defined(OVERRIDE_silk_NSQ_del_dec) -#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ +#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_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + ((void)(arch),silk_NSQ_del_dec_c(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 @@ -350,7 +346,6 @@ 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 */ ); diff --git a/thirdparty/opus/silk/mips/NSQ_del_dec_mipsr1.h b/thirdparty/opus/silk/mips/NSQ_del_dec_mipsr1.h index cd70713a8f..ad1cfe2a9b 100644 --- a/thirdparty/opus/silk/mips/NSQ_del_dec_mipsr1.h +++ b/thirdparty/opus/silk/mips/NSQ_del_dec_mipsr1.h @@ -61,7 +61,7 @@ static inline void silk_noise_shape_quantizer_del_dec( 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 *smpl_buf_idx, /* I Index to newest samples in buffers */ opus_int decisionDelay, /* I */ int arch /* I */ ) @@ -323,9 +323,8 @@ static inline void silk_noise_shape_quantizer_del_dec( 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; + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */ + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */ /* Find winner */ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; diff --git a/thirdparty/opus/silk/mips/sigproc_fix_mipsr1.h b/thirdparty/opus/silk/mips/sigproc_fix_mipsr1.h index 51520c0a6f..3b0a695365 100644 --- a/thirdparty/opus/silk/mips/sigproc_fix_mipsr1.h +++ b/thirdparty/opus/silk/mips/sigproc_fix_mipsr1.h @@ -28,6 +28,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef SILK_SIGPROC_FIX_MIPSR1_H #define SILK_SIGPROC_FIX_MIPSR1_H +#ifdef __cplusplus +extern "C" +{ +#endif + #undef silk_SAT16 static inline short int silk_SAT16(int a) { diff --git a/thirdparty/opus/silk/process_NLSFs.c b/thirdparty/opus/silk/process_NLSFs.c index d130809541..0ab71f0163 100644 --- a/thirdparty/opus/silk/process_NLSFs.c +++ b/thirdparty/opus/silk/process_NLSFs.c @@ -48,7 +48,7 @@ void silk_process_NLSFs( 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 ) ); + silk_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); /***********************/ /* Calculate mu values */ @@ -60,7 +60,7 @@ void silk_process_NLSFs( NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); } - celt_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 > 0 ); silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); /* Calculate NLSF weights */ @@ -89,7 +89,7 @@ void silk_process_NLSFs( 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 ); + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder ); if( doInterpolate ) { /* Calculate the interpolated, quantized LSF vector for the first half */ @@ -97,11 +97,11 @@ void silk_process_NLSFs( psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); /* Convert back to LPC coefficients */ - silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder, psEncC->arch ); + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder ); } else { /* Copy LPC coefficients for first half from second half */ - celt_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER ); + silk_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER ); silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); } } diff --git a/thirdparty/opus/silk/quant_LTP_gains.c b/thirdparty/opus/silk/quant_LTP_gains.c index d6b8eff8d1..513a8c4468 100644 --- a/thirdparty/opus/silk/quant_LTP_gains.c +++ b/thirdparty/opus/silk/quant_LTP_gains.c @@ -33,15 +33,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "tuning_parameters.h" void silk_quant_LTP_gains( - opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)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 */ + const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ + opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ + opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr, /* I number of subframes */ int arch /* I Run-time architecture */ ) { @@ -50,16 +49,16 @@ void silk_quant_LTP_gains( 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; + const opus_int16 *b_Q14_ptr; + const opus_int32 *W_Q18_ptr; + opus_int32 rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14; + opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7, gain_Q7; /***************************************************/ /* iterate over different codebooks with different */ /* rates/distortions, and choose best */ /***************************************************/ - min_rate_dist_Q7 = silk_int32_MAX; + min_rate_dist_Q14 = 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 @@ -71,47 +70,53 @@ void silk_quant_LTP_gains( 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; + /* Set up pointer to first subframe */ + W_Q18_ptr = W_Q18; + b_Q14_ptr = B_Q14; - res_nrg_Q15 = 0; - rate_dist_Q7 = 0; + rate_dist_Q14 = 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 */ + &rate_dist_Q14_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 */ + b_Q14_ptr, /* I input vector to be quantized */ + W_Q18_ptr, /* I weighting matrix */ 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 */ + mu_Q9, /* I tradeoff between weighted error and rate */ 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 ); + rate_dist_Q14 = silk_ADD_POS_SAT32( rate_dist_Q14, rate_dist_Q14_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; + b_Q14_ptr += LTP_ORDER; + W_Q18_ptr += LTP_ORDER * LTP_ORDER; } - if( rate_dist_Q7 <= min_rate_dist_Q7 ) { - min_rate_dist_Q7 = rate_dist_Q7; + /* Avoid never finding a codebook */ + rate_dist_Q14 = silk_min( silk_int32_MAX - 1, rate_dist_Q14 ); + + if( rate_dist_Q14 < min_rate_dist_Q14 ) { + min_rate_dist_Q14 = rate_dist_Q14; *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; } + + /* Break early in low-complexity mode if rate distortion is below threshold */ + if( lowComplexity && ( rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14 ) ) { + break; + } } cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; @@ -120,13 +125,5 @@ void silk_quant_LTP_gains( 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/thirdparty/opus/silk/resampler.c b/thirdparty/opus/silk/resampler.c index 1f11e50891..374fbb3722 100644 --- a/thirdparty/opus/silk/resampler.c +++ b/thirdparty/opus/silk/resampler.c @@ -91,14 +91,14 @@ opus_int silk_resampler_init( 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 ); + silk_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 ); + silk_assert( 0 ); return -1; } S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; @@ -151,7 +151,7 @@ opus_int silk_resampler_init( S->Coefs = silk_Resampler_1_6_COEFS; } else { /* None available */ - celt_assert( 0 ); + silk_assert( 0 ); return -1; } } else { @@ -181,9 +181,9 @@ opus_int silk_resampler( opus_int nSamples; /* Need at least 1 ms of input data */ - celt_assert( inLen >= S->Fs_in_kHz ); + silk_assert( inLen >= S->Fs_in_kHz ); /* Delay can't exceed the 1 ms of buffering */ - celt_assert( S->inputDelay <= S->Fs_in_kHz ); + silk_assert( S->inputDelay <= S->Fs_in_kHz ); nSamples = S->Fs_in_kHz - S->inputDelay; diff --git a/thirdparty/opus/silk/resampler_down2.c b/thirdparty/opus/silk/resampler_down2.c index 971d7bfd4a..cec3634640 100644 --- a/thirdparty/opus/silk/resampler_down2.c +++ b/thirdparty/opus/silk/resampler_down2.c @@ -43,8 +43,8 @@ void silk_resampler_down2( 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 ); + silk_assert( silk_resampler_down2_0 > 0 ); + silk_assert( silk_resampler_down2_1 < 0 ); /* Internal variables and state are in Q10 format */ for( k = 0; k < len2; k++ ) { diff --git a/thirdparty/opus/silk/resampler_private_down_FIR.c b/thirdparty/opus/silk/resampler_private_down_FIR.c index 3e8735a35a..783e42b356 100644 --- a/thirdparty/opus/silk/resampler_private_down_FIR.c +++ b/thirdparty/opus/silk/resampler_private_down_FIR.c @@ -136,7 +136,7 @@ static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL( } break; default: - celt_assert( 0 ); + silk_assert( 0 ); } return out; } diff --git a/thirdparty/opus/silk/sort.c b/thirdparty/opus/silk/sort.c index 4fba16f831..7187c9efb1 100644 --- a/thirdparty/opus/silk/sort.c +++ b/thirdparty/opus/silk/sort.c @@ -48,9 +48,9 @@ void silk_insertion_sort_increasing( opus_int i, j; /* Safety checks */ - celt_assert( K > 0 ); - celt_assert( L > 0 ); - celt_assert( L >= K ); + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); /* Write start indices in index vector */ for( i = 0; i < K; i++ ) { @@ -96,9 +96,9 @@ void silk_insertion_sort_decreasing_int16( opus_int value; /* Safety checks */ - celt_assert( K > 0 ); - celt_assert( L > 0 ); - celt_assert( L >= K ); + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); /* Write start indices in index vector */ for( i = 0; i < K; i++ ) { @@ -141,7 +141,7 @@ void silk_insertion_sort_increasing_all_values_int16( opus_int i, j; /* Safety checks */ - celt_assert( L > 0 ); + silk_assert( L > 0 ); /* Sort vector elements by value, increasing order */ for( i = 1; i < L; i++ ) { diff --git a/thirdparty/opus/silk/stereo_LR_to_MS.c b/thirdparty/opus/silk/stereo_LR_to_MS.c index c8226663c8..dda0298de2 100644 --- a/thirdparty/opus/silk/stereo_LR_to_MS.c +++ b/thirdparty/opus/silk/stereo_LR_to_MS.c @@ -109,7 +109,7 @@ void silk_stereo_LR_to_MS( if( total_rate_bps < 1 ) { total_rate_bps = 1; } - min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 600 ); + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 ); 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 ); diff --git a/thirdparty/opus/silk/stereo_encode_pred.c b/thirdparty/opus/silk/stereo_encode_pred.c index 03becb6736..e6dd195066 100644 --- a/thirdparty/opus/silk/stereo_encode_pred.c +++ b/thirdparty/opus/silk/stereo_encode_pred.c @@ -41,11 +41,11 @@ void silk_stereo_encode_pred( /* Entropy coding */ n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; - celt_assert( n < 25 ); + silk_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 ); + silk_assert( ix[ n ][ 0 ] < 3 ); + silk_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 ); } diff --git a/thirdparty/opus/silk/structs.h b/thirdparty/opus/silk/structs.h index 3380c757b2..827829dc6f 100644 --- a/thirdparty/opus/silk/structs.h +++ b/thirdparty/opus/silk/structs.h @@ -48,7 +48,6 @@ typedef struct { 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; @@ -78,7 +77,6 @@ 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 */ @@ -88,7 +86,6 @@ typedef struct { 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; @@ -172,6 +169,8 @@ typedef struct { 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_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */ + opus_int mu_LTP_Q9; /* Rate-distortion tradeoff in LTP quantization */ 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 */ @@ -302,7 +301,6 @@ typedef struct { /* Stuff used for PLC */ opus_int lossCnt; opus_int prevSignalType; - int arch; silk_PLC_struct sPLC; diff --git a/thirdparty/opus/silk/sum_sqr_shift.c b/thirdparty/opus/silk/sum_sqr_shift.c index 4fd0c3d7d5..129df191d8 100644 --- a/thirdparty/opus/silk/sum_sqr_shift.c +++ b/thirdparty/opus/silk/sum_sqr_shift.c @@ -41,40 +41,43 @@ void silk_sum_sqr_shift( ) { opus_int i, shft; - opus_uint32 nrg_tmp; - opus_int32 nrg; + opus_int32 nrg_tmp, 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 ); + nrg = 0; + shft = 0; + len--; + for( i = 0; i < len; i += 2 ) { + nrg = silk_SMLABB_ovflw( nrg, x[ i ], x[ i ] ); + nrg = silk_SMLABB_ovflw( nrg, x[ i + 1 ], x[ i + 1 ] ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft = 2; + i+=2; + break; + } } - 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 ) { + for( ; i < len; 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 ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, (opus_uint32)nrg_tmp, shft ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft += 2; + } } - if( i < len ) { + 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 to have at least one extra leading zero (two leading zeros in total) */ + if( nrg & 0xC0000000 ) { + nrg = silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft += 2; + } /* Output arguments */ *shift = shft; diff --git a/thirdparty/opus/silk/tables.h b/thirdparty/opus/silk/tables.h index 95230c451a..7fea6fda39 100644 --- a/thirdparty/opus/silk/tables.h +++ b/thirdparty/opus/silk/tables.h @@ -76,8 +76,10 @@ extern const opus_uint8 silk_NLSF_EXT_iCDF[ 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_int16 silk_LTP_gain_middle_avg_RD_Q14; 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 */ @@ -97,6 +99,12 @@ extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +extern const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; /* 32 */ + /* Quantization offsets */ extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ diff --git a/thirdparty/opus/silk/tables_LTP.c b/thirdparty/opus/silk/tables_LTP.c index 5e12c8643e..0e6a0254d5 100644 --- a/thirdparty/opus/silk/tables_LTP.c +++ b/thirdparty/opus/silk/tables_LTP.c @@ -51,6 +51,8 @@ static const opus_uint8 silk_LTP_gain_iCDF_2[32] = { 24, 20, 16, 12, 9, 5, 2, 0 }; +const opus_int16 silk_LTP_gain_middle_avg_RD_Q14 = 12304; + static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { 15, 131, 138, 138, 155, 155, 173, 173 }; diff --git a/thirdparty/opus/silk/tables_NLSF_CB_NB_MB.c b/thirdparty/opus/silk/tables_NLSF_CB_NB_MB.c index 195d5b95bd..8c59d207aa 100644 --- a/thirdparty/opus/silk/tables_NLSF_CB_NB_MB.c +++ b/thirdparty/opus/silk/tables_NLSF_CB_NB_MB.c @@ -74,41 +74,6 @@ static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { 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, @@ -185,7 +150,6 @@ const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = 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, diff --git a/thirdparty/opus/silk/tables_NLSF_CB_WB.c b/thirdparty/opus/silk/tables_NLSF_CB_WB.c index 5cc9f57bff..50af87eb2e 100644 --- a/thirdparty/opus/silk/tables_NLSF_CB_WB.c +++ b/thirdparty/opus/silk/tables_NLSF_CB_WB.c @@ -98,41 +98,6 @@ static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { 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, @@ -223,7 +188,6 @@ const silk_NLSF_CB_struct silk_NLSF_CB_WB = 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, diff --git a/thirdparty/opus/silk/tables_other.c b/thirdparty/opus/silk/tables_other.c index e34d90777b..398686bf26 100644 --- a/thirdparty/opus/silk/tables_other.c +++ b/thirdparty/opus/silk/tables_other.c @@ -38,6 +38,20 @@ extern "C" { #endif +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = { + 0, 8000, 9400, 11500, 13500, 17500, 25000, MAX_TARGET_RATE_BPS +}; +const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = { + 0, 9000, 12000, 14500, 18500, 24500, 35500, MAX_TARGET_RATE_BPS +}; +const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = { + 0, 10500, 14000, 17000, 21500, 28500, 42000, MAX_TARGET_RATE_BPS +}; +const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = { + 18, 29, 38, 40, 46, 52, 62, 84 +}; + /* 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, diff --git a/thirdparty/opus/silk/tuning_parameters.h b/thirdparty/opus/silk/tuning_parameters.h index d70275fd8f..5b8f404235 100644 --- a/thirdparty/opus/silk/tuning_parameters.h +++ b/thirdparty/opus/silk/tuning_parameters.h @@ -53,12 +53,19 @@ extern "C" /* LPC analysis regularization */ #define FIND_LPC_COND_FAC 1e-5f +/* LTP analysis defines */ +#define FIND_LTP_COND_FAC 1e-5f +#define LTP_DAMPING 0.05f +#define LTP_SMOOTHING 0.1f + +/* LTP quantization settings */ +#define MU_LTP_QUANT_NB 0.03f +#define MU_LTP_QUANT_MB 0.025f +#define MU_LTP_QUANT_WB 0.02f + /* 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 */ /***********************/ @@ -96,16 +103,25 @@ extern "C" #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 +#define SPARSENESS_THRESHOLD_QNT_OFFSET 0.75f /* warping control */ #define WARPING_MULTIPLIER 0.015f /* fraction added to first autocorrelation value */ -#define SHAPE_WHITE_NOISE_FRACTION 3e-5f +#define SHAPE_WHITE_NOISE_FRACTION 5e-5f /* noise shaping filter chirp factor */ -#define BANDWIDTH_EXPANSION 0.94f +#define BANDWIDTH_EXPANSION 0.95f + +/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */ +#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA 0.01f + +/* extra harmonic boosting (signal shaping) at low bitrates */ +#define LOW_RATE_HARMONIC_BOOST 0.1f + +/* extra harmonic boosting (signal shaping) for noisy input signals */ +#define LOW_INPUT_QUALITY_HARMONIC_BOOST 0.1f /* harmonic noise shaping */ #define HARMONIC_SHAPING 0.3f diff --git a/thirdparty/opus/silk/x86/NSQ_del_dec_sse4_1.c b/thirdparty/opus/silk/x86/NSQ_del_dec_sse.c index 2c75ede2dd..21d4a8bc1e 100644 --- a/thirdparty/opus/silk/x86/NSQ_del_dec_sse4_1.c +++ b/thirdparty/opus/silk/x86/NSQ_del_dec_sse.c @@ -107,12 +107,12 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( 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 *smpl_buf_idx, /* I 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 */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -234,8 +234,7 @@ void silk_NSQ_del_dec_sse4_1( 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; + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; 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 ) ); @@ -247,7 +246,7 @@ void silk_NSQ_del_dec_sse4_1( /* Rewhiten with new A coefs */ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; - celt_assert( start_idx > 0 ); + 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 ); @@ -286,8 +285,7 @@ void silk_NSQ_del_dec_sse4_1( 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; + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; 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 ) ); @@ -301,6 +299,7 @@ void silk_NSQ_del_dec_sse4_1( NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; /* Save quantized speech signal */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */ 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; @@ -334,7 +333,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( 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 *smpl_buf_idx, /* I Index to newest samples in buffers */ opus_int decisionDelay /* I */ ) { @@ -353,7 +352,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( __m128i b_Q12_0123, b_sr_Q12_0123; SAVE_STACK; - celt_assert( nStatesDelayedDecision > 0 ); + silk_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 ]; @@ -639,9 +638,8 @@ static OPUS_INLINE void silk_noise_shape_quantizer_del_dec_sse4_1( 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; + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */ + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */ /* Find winner */ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; diff --git a/thirdparty/opus/silk/x86/NSQ_sse4_1.c b/thirdparty/opus/silk/x86/NSQ_sse.c index b0315e35fc..bb3c5f1955 100644 --- a/thirdparty/opus/silk/x86/NSQ_sse4_1.c +++ b/thirdparty/opus/silk/x86/NSQ_sse.c @@ -71,7 +71,7 @@ static OPUS_INLINE void silk_noise_shape_quantizer_10_16_sse4_1( ); void silk_NSQ_sse4_1( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -199,7 +199,7 @@ void silk_NSQ_sse4_1( 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_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 ); @@ -233,6 +233,7 @@ void silk_NSQ_sse4_1( NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; /* Save quantized speech and noise shaping signals */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */ 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; diff --git a/thirdparty/opus/silk/x86/VAD_sse4_1.c b/thirdparty/opus/silk/x86/VAD_sse.c index d02ddf4ad0..4e90f4410d 100644 --- a/thirdparty/opus/silk/x86/VAD_sse4_1.c +++ b/thirdparty/opus/silk/x86/VAD_sse.c @@ -65,9 +65,9 @@ opus_int silk_VAD_GetSA_Q8_sse4_1( /* O Return value, 0 if s /* 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 ) ); + silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + silk_assert( psEncC->frame_length <= 512 ); + silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); /***********************/ /* Filter and Decimate */ diff --git a/thirdparty/opus/silk/x86/VQ_WMat_EC_sse4_1.c b/thirdparty/opus/silk/x86/VQ_WMat_EC_sse.c index 74d6c6d0ec..74d6c6d0ec 100644 --- a/thirdparty/opus/silk/x86/VQ_WMat_EC_sse4_1.c +++ b/thirdparty/opus/silk/x86/VQ_WMat_EC_sse.c diff --git a/thirdparty/opus/silk/x86/main_sse.h b/thirdparty/opus/silk/x86/main_sse.h index 2f15d44869..d8d61310ed 100644 --- a/thirdparty/opus/silk/x86/main_sse.h +++ b/thirdparty/opus/silk/x86/main_sse.h @@ -34,7 +34,6 @@ # 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( @@ -80,13 +79,11 @@ extern void (*const SILK_VQ_WMAT_EC_IMPL[OPUS_ARCHMASK + 1])( 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 */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -113,7 +110,7 @@ void silk_NSQ_sse4_1( #else extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -140,7 +137,7 @@ extern void (*const SILK_NSQ_IMPL[OPUS_ARCHMASK + 1])( # define OVERRIDE_silk_NSQ_del_dec void silk_NSQ_del_dec_sse4_1( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -167,7 +164,7 @@ void silk_NSQ_del_dec_sse4_1( #else extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( - const silk_encoder_state *psEncC, /* I Encoder State */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -190,7 +187,6 @@ extern void (*const SILK_NSQ_DEL_DEC_IMPL[OPUS_ARCHMASK + 1])( 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 */ @@ -242,6 +238,39 @@ extern opus_int (*const SILK_VAD_GETSA_Q8_IMPL[OPUS_ARCHMASK + 1])( silk_encoder_state *psEnC, const opus_int16 pIn[]); +# define OVERRIDE_silk_warped_LPC_analysis_filter_FIX + +#endif + +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) */ +); + +#if defined(OPUS_X86_PRESUME_SSE4_1) +#define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \ + ((void)(arch),silk_warped_LPC_analysis_filter_FIX_c(state, res_Q2, coef_Q13, input, lambda_Q16, length, order)) + +#else + +extern void (*const SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[OPUS_ARCHMASK + 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) */ +); + +# define silk_warped_LPC_analysis_filter_FIX(state, res_Q2, coef_Q13, input, lambda_Q16, length, order, arch) \ + ((*SILK_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[(arch) & OPUS_ARCHMASK])(state, res_Q2, coef_Q13, input, lambda_Q16, length, order)) + #endif # endif diff --git a/thirdparty/opus/silk/x86/x86_silk_map.c b/thirdparty/opus/silk/x86/x86_silk_map.c index 32dcc3cab7..818841f2c1 100644 --- a/thirdparty/opus/silk/x86/x86_silk_map.c +++ b/thirdparty/opus/silk/x86/x86_silk_map.c @@ -66,9 +66,8 @@ opus_int (*const SILK_VAD_GETSA_Q8_IMPL[ OPUS_ARCHMASK + 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 */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -90,9 +89,7 @@ void (*const SILK_NSQ_IMPL[ OPUS_ARCHMASK + 1 ] )( 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 */ @@ -112,11 +109,9 @@ void (*const SILK_VQ_WMAT_EC_IMPL[ OPUS_ARCHMASK + 1 ] )( 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 */ + const silk_encoder_state *psEncC, /* I/O 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 */ @@ -138,10 +133,25 @@ void (*const SILK_NSQ_DEL_DEC_IMPL[ OPUS_ARCHMASK + 1 ] )( 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_WARPED_LPC_ANALYSIS_FILTER_FIX_IMPL[ OPUS_ARCHMASK + 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) */ +) = { + silk_warped_LPC_analysis_filter_FIX_c, /* non-sse */ + silk_warped_LPC_analysis_filter_FIX_c, + silk_warped_LPC_analysis_filter_FIX_c, + MAY_HAVE_SSE4_1( silk_warped_LPC_analysis_filter_FIX ), /* sse4.1 */ + MAY_HAVE_SSE4_1( silk_warped_LPC_analysis_filter_FIX ) /* avx */ +}; + 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 */ diff --git a/thirdparty/opus/stream.c b/thirdparty/opus/stream.c index 6a85197a66..0238a6b31b 100644 --- a/thirdparty/opus/stream.c +++ b/thirdparty/opus/stream.c @@ -235,7 +235,8 @@ void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){ fp=fopen(_path,_mode); #else fp=NULL; - { + if(_path==NULL||_mode==NULL)errno=EINVAL; + else{ wchar_t *wpath; wchar_t *wmode; wpath=op_utf8_to_utf16(_path); @@ -265,7 +266,8 @@ void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode, fp=freopen(_path,_mode,(FILE *)_stream); #else fp=NULL; - { + if(_path==NULL||_mode==NULL)errno=EINVAL; + else{ wchar_t *wpath; wchar_t *wmode; wpath=op_utf8_to_utf16(_path); |