-\r
-/*\r
- * Copyright (c) CompanyNameMagicTag 2021-2022. All rights reserved.\r
- * Description: Application core board init function for standard\r
- * Author:\r
- * Create:\r
- */\r
-\r
-#ifdef __LITEOS__\r
-#include "partition.h"\r
-#endif\r
-#include "pm.h"\r
-#include "cpu_utils.h"\r
-#include "log_common.h"\r
-#include "log_uart.h"\r
-#include "exception.h"\r
-#include "log_oml_exception.h"\r
-#ifdef HSO_SUPPORT\r
-#include "dfx_system_init.h"\r
-#endif\r
-#include "debug_print.h"\r
-#ifdef SUPPORT_AT_GRAPHIC\r
-#include "graphic_cmd_manager.h"\r
-#endif\r
-#ifdef SUPPORT_AT_JSINSTALL\r
-#include "ohosfwk_at_process.h"\r
-#endif\r
-#ifdef SUPPORT_AT_APP\r
-#include "app_cmd_manager.h"\r
-#endif\r
-#ifdef SUPPORT_AT_AUDIO\r
-#include "audio_cmd_manager.h"\r
-#endif\r
-#ifdef SUPPORT_AT_BT_MANAGER\r
-#include "bt_manager_cmd_manager.h"\r
-#endif\r
-#ifdef SUPPORT_AT_MEDIA\r
-#include "media_cmd_manager.h"\r
-#endif\r
-#ifdef SUPPORT_AT_PPG\r
-#include "ppg_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_VIBRATOR\r
-#include "vibrator_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_HX3507\r
-#include "hx3507_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_BATTERY\r
-#include "battery_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_LIS2DOC\r
-#include "lis2doc_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_CYWEE\r
-#include "cywee_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_MAG\r
-#include "mag_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_CUSTOMUTILS\r
-#include "custom_utils_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_CAT1\r
-#include "cat1_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_PPP\r
-#include "ppp_at_cmd.h"\r
-#endif\r
-#include "log_file.h"\r
-#ifdef CONFIG_OTA_UPDATE_SUPPORT\r
-#include "upg.h"\r
-#endif\r
-#ifdef SUPPORT_AT_HX3508\r
-#include "hx3508_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_LQBP002TA\r
-#include "lqbp_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_CHARGE\r
-#include "charge_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_CROWN\r
-#include "crown_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_MIXO\r
-#include "mixo_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_GYRO\r
-#include "gyro_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_BP\r
-#include "bp_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_AT_LEINIAO_API\r
-#include "leiniao_api_at.h"\r
-#endif\r
-#ifdef SUPPORT_ZHIHUI_AI_SERVICE\r
-#include "ai_at_cmd.h"\r
-#endif\r
-#ifdef SUPPORT_ZHIHUI_AI_OLD\r
-#include "ai_old_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_ZHIHUI_AI_NEW\r
-#include "ai_V2_5_at_cmd.h"\r
-#endif\r
-\r
-#ifdef ENABLE_VAD_SERVER\r
-#include "imsl_at_cmd.h"\r
-#endif\r
-\r
-#ifdef SUPPORT_ZHIHUI_DMP\r
-#include "dmp_api_at.h"\r
-#endif\r
-\r
-static void register_at_service(void)\r
-{\r
-#ifdef SUPPORT_AT_GRAPHIC\r
- uint32_t graphic_cmd_count;\r
- at_cmd_table_t *graphic_table = get_graphic_cmd_table(&graphic_cmd_count);\r
- at_cmd_add_moudle(graphic_table, graphic_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_JSINSTALL\r
- uint32_t ohosfwk_cmd_count;\r
- at_cmd_table_t *ohosfwk_table = get_ohosfwk_cmd_table(&ohosfwk_cmd_count);\r
- at_cmd_add_moudle(ohosfwk_table, ohosfwk_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_APP\r
- uint32_t app_cmd_count;\r
- at_cmd_table_t *app_table = get_app_cmd_table(&app_cmd_count);\r
- at_cmd_add_moudle(app_table, app_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_AUDIO\r
- uint32_t audio_cmd_count;\r
- at_cmd_table_t *audio_table = get_audio_cmd_table(&audio_cmd_count);\r
- at_cmd_add_moudle(audio_table, audio_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_BT_MANAGER\r
- uint32_t bt_manager_cmd_count;\r
- at_cmd_table_t *bt_manager_table = get_bt_manager_cmd_table(&bt_manager_cmd_count);\r
- at_cmd_add_moudle(bt_manager_table, bt_manager_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_MEDIA\r
- uint32_t media_cmd_count;\r
- at_cmd_table_t *media_table = get_media_cmd_table(&media_cmd_count);\r
- at_cmd_add_moudle(media_table, media_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_PPG\r
- uint32_t hx3695_cmd_count;\r
- at_cmd_table_t *hx3695_table = get_ppg_cmd_table(&hx3695_cmd_count);\r
- at_cmd_add_moudle(hx3695_table, hx3695_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_VIBRATOR\r
- uint32_t vibrator_cmd_count;\r
- at_cmd_table_t *vibrator_table = get_vibrator_cmd_table(&vibrator_cmd_count);\r
- at_cmd_add_moudle(vibrator_table, vibrator_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_HX3507\r
- uint32_t hx3507_cmd_count;\r
- at_cmd_table_t *hx3507_table = get_hx3507_cmd_table(&hx3507_cmd_count);\r
- at_cmd_add_moudle(hx3507_table, hx3507_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_BATTERY\r
- uint32_t battery_cmd_count;\r
- at_cmd_table_t *battery_table = get_battery_cmd_table(&battery_cmd_count);\r
- at_cmd_add_moudle(battery_table, battery_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_CUSTOMUTILS\r
- uint32_t custom_utils_cmd_count;\r
- at_cmd_table_t *custom_utils_table = get_custom_utils_cmd_table(&custom_utils_cmd_count);\r
- at_cmd_add_moudle(custom_utils_table, custom_utils_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_CAT1\r
- uint32_t cat1_cmd_count;\r
- at_cmd_table_t *cat1_table = get_cat1_cmd_table(&cat1_cmd_count);\r
- at_cmd_add_moudle(cat1_table, cat1_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_PPP\r
- uint32_t ppp_cmd_count;\r
- at_cmd_table_t *ppp_table = get_ppp_cmd_table(&ppp_cmd_count);\r
- at_cmd_add_moudle(ppp_table, ppp_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_ZHIHUI_AI_OLD\r
- uint32_t ai_old_cmd_count;\r
- at_cmd_table_t *ai_old_table = get_ai_old_cmd_table(&ai_old_cmd_count);\r
- at_cmd_add_moudle(ai_old_table, ai_old_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_ZHIHUI_AI_NEW\r
- uint32_t ai_new_cmd_count;\r
- at_cmd_table_t *ai_new_table = get_ai_2_5_cmd_table(&ai_new_cmd_count);\r
- at_cmd_add_moudle(ai_new_table, ai_new_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_LIS2DOC\r
- uint32_t lis2doc_cmd_count;\r
- at_cmd_table_t *lis2doc_table = get_lis2doc_cmd_table(&lis2doc_cmd_count);\r
- at_cmd_add_moudle(lis2doc_table, lis2doc_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_CYWEE\r
- uint32_t cywee_cmd_count;\r
- at_cmd_table_t *cywee_table = get_cywee_cmd_table(&cywee_cmd_count);\r
- at_cmd_add_moudle(cywee_table, cywee_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_MAG\r
- uint32_t mag_cmd_count;\r
- at_cmd_table_t *mag_table = get_mag_cmd_table(&mag_cmd_count);\r
- at_cmd_add_moudle(mag_table, mag_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_AT_RTCTEST\r
- uint32_t rtc_cmd_count;\r
- at_cmd_table_t *rtc_table = get_rtc_cmd_table(&rtc_cmd_count);\r
- at_cmd_add_moudle(rtc_table, rtc_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_HX3508\r
- uint32_t hx3508_cmd_count;\r
- at_cmd_table_t *hx3508_table = get_hx3508_cmd_table(&hx3508_cmd_count);\r
- at_cmd_add_moudle(hx3508_table, hx3508_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_LQBP002TA\r
- uint32_t lqbp002ta_cmd_count;\r
- at_cmd_table_t *lqbp002ta_table = get_lqbp002ta_cmd_table(&lqbp002ta_cmd_count);\r
- at_cmd_add_moudle(lqbp002ta_table, lqbp002ta_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_CHARGE\r
- uint32_t charge_cmd_count;\r
- at_cmd_table_t *charge_table = get_charge_cmd_table(&charge_cmd_count);\r
- at_cmd_add_moudle(charge_table, charge_cmd_count); \r
-#endif\r
-#ifdef SUPPORT_AT_CROWN\r
- uint32_t crown_cmd_count;\r
- at_cmd_table_t *crown_table = get_crown_cmd_table(&crown_cmd_count);\r
- at_cmd_add_moudle(crown_table, crown_cmd_count); \r
-#endif\r
-#ifdef SUPPORT_AT_MIXO\r
- uint32_t mixo_cmd_count;\r
- at_cmd_table_t *mixo_table = get_mixo_cmd_table(&mixo_cmd_count);\r
- at_cmd_add_moudle(mixo_table, mixo_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_GYRO\r
- uint32_t gyro_cmd_count;\r
- at_cmd_table_t *gyro_table = get_gyro_cmd_table(&gyro_cmd_count);\r
- at_cmd_add_moudle(gyro_table, gyro_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_BP\r
- uint32_t bp_cmd_count;\r
- at_cmd_table_t *bp_table = get_bp_cmd_table(&bp_cmd_count);\r
- at_cmd_add_moudle(bp_table, bp_cmd_count);\r
-#endif\r
-#ifdef SUPPORT_AT_LEINIAO_API\r
- uint32_t leiniao_api_cmd_count;\r
- at_cmd_table_t *leiniao_api_table = get_leiniao_api_cmd_table(&leiniao_api_cmd_count);\r
- at_cmd_add_moudle(leiniao_api_table, leiniao_api_cmd_count);\r
-#endif\r
-\r
-#ifdef SUPPORT_ZHIHUI_AI_SERVICE\r
- uint32_t ai_cmd_count;\r
- at_cmd_table_t *ai_table = get_ai_cmd_table(&ai_cmd_count);\r
- at_cmd_add_moudle(ai_table, ai_cmd_count);\r
-#endif\r
-\r
-#ifdef ENABLE_VAD_SERVER\r
- uint32_t imsl_vad_cmd_count;\r
- at_cmd_table_t *imsl_vad_table = get_imsl_vad_at_cmd_table(&imsl_vad_cmd_count);\r
- at_cmd_add_moudle(imsl_vad_table, imsl_vad_cmd_count);\r
-#endif\r
-\r
-\r
-#ifdef SUPPORT_ZHIHUI_DMP\r
- uint32_t dmp_api_cmd_count;\r
- at_cmd_table_t *dmp_api_table = get_dmp_api_cmd_table(&dmp_api_cmd_count);\r
- at_cmd_add_moudle(dmp_api_table, dmp_api_cmd_count);\r
-#endif\r
-\r
-}\r
-\r
-#ifdef CONFIG_OTA_UPDATE_SUPPORT\r
-static void upg_putc(const char c)\r
-{\r
- printf("%c", c);\r
-}\r
-#endif\r
-\r
-void service_init(void)\r
-{\r
-#if defined(FREERTOS_TEST)\r
- // freertos demo test\r
- extern int main_full(void);\r
- (void)main_full();\r
- for (;;) {\r
- }\r
-#endif\r
-\r
- /* dfx init step 1: log init */\r
- log_init();\r
- log_init_after_rtos();\r
- log_uart_init_after_rtos();\r
-\r
- cpu_utils_init();\r
- hal_register_exception_dump_callback(log_exception_dump);\r
- uapi_partition_init();\r
- PRINT("partition init success"NEWLINE);\r
-\r
-#ifdef CONFIG_OTA_UPDATE_SUPPORT\r
- upg_func_t upg_func = {0};\r
- upg_func.malloc = malloc;\r
- upg_func.free = free;\r
- upg_func.serial_putc = upg_putc;\r
- (void)uapi_upg_init(&upg_func);\r
- PRINT("upg init success\r\n");\r
-#endif\r
- crypto_drv_init();\r
- uapi_nv_init();\r
-#ifdef SUPPORT_AT_BT_MANAGER\r
- set_calibration_from_nv();\r
-#endif\r
- /* dfx init step 2: dfx init */\r
-#ifdef HSO_SUPPORT\r
- dfx_system_init();\r
-#endif\r
- /* power manager init */\r
- uapi_pm_init();\r
-#ifdef SUPPORT_POWER_MANAGER\r
- uapi_power_display_init();\r
-#endif\r
-\r
- register_at_service();\r
-}\r
+
+/*
+ * Copyright (c) CompanyNameMagicTag 2021-2022. All rights reserved.
+ * Description: Application core board init function for standard
+ * Author:
+ * Create:
+ */
+
+#ifdef __LITEOS__
+#include "partition.h"
+#endif
+#include "pm.h"
+#include "cpu_utils.h"
+#include "log_common.h"
+#include "log_uart.h"
+#include "exception.h"
+#include "log_oml_exception.h"
+#ifdef HSO_SUPPORT
+#include "dfx_system_init.h"
+#endif
+#include "debug_print.h"
+#ifdef SUPPORT_AT_GRAPHIC
+#include "graphic_cmd_manager.h"
+#endif
+#ifdef SUPPORT_AT_JSINSTALL
+#include "ohosfwk_at_process.h"
+#endif
+#ifdef SUPPORT_AT_APP
+#include "app_cmd_manager.h"
+#endif
+#ifdef SUPPORT_AT_AUDIO
+#include "audio_cmd_manager.h"
+#endif
+#ifdef SUPPORT_AT_BT_MANAGER
+#include "bt_manager_cmd_manager.h"
+#endif
+#ifdef SUPPORT_AT_MEDIA
+#include "media_cmd_manager.h"
+#endif
+#ifdef SUPPORT_AT_PPG
+#include "ppg_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_VIBRATOR
+#include "vibrator_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_HX3507
+#include "hx3507_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_BATTERY
+#include "battery_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_LIS2DOC
+#include "lis2doc_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_CYWEE
+#include "cywee_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_MAG
+#include "mag_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_AT_CUSTOMUTILS
+#include "custom_utils_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_CAT1
+#include "cat1_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_PPP
+#include "ppp_at_cmd.h"
+#endif
+#include "log_file.h"
+#ifdef CONFIG_OTA_UPDATE_SUPPORT
+#include "upg.h"
+#endif
+#ifdef SUPPORT_AT_HX3508
+#include "hx3508_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_LQBP002TA
+#include "lqbp_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_CHARGE
+#include "charge_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_CROWN
+#include "crown_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_MIXO
+#include "mixo_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_GYRO
+#include "gyro_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_BP
+#include "bp_at_cmd.h"
+#endif
+#ifdef SUPPORT_AT_LEINIAO_API
+#include "leiniao_api_at.h"
+#include "uapi_mqtt_at.h"
+#include "ln_mqtt_api_at.h"
+#endif
+#ifdef SUPPORT_ZHIHUI_AI_SERVICE
+#include "ai_at_cmd.h"
+#endif
+#ifdef SUPPORT_ZHIHUI_AI_OLD
+#include "ai_old_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_ZHIHUI_AI_NEW
+#include "ai_V2_5_at_cmd.h"
+#endif
+
+#ifdef ENABLE_VAD_SERVER
+#include "imsl_at_cmd.h"
+#endif
+
+#ifdef SUPPORT_ZHIHUI_DMP
+#include "dmp_api_at.h"
+#endif
+
+#ifdef SUPPORT_AT_AI_API
+#include "ai_api_at.h"
+#endif
+
+static void register_at_service(void)
+{
+#ifdef SUPPORT_AT_GRAPHIC
+ uint32_t graphic_cmd_count;
+ at_cmd_table_t *graphic_table = get_graphic_cmd_table(&graphic_cmd_count);
+ at_cmd_add_moudle(graphic_table, graphic_cmd_count);
+#endif
+#ifdef SUPPORT_AT_JSINSTALL
+ uint32_t ohosfwk_cmd_count;
+ at_cmd_table_t *ohosfwk_table = get_ohosfwk_cmd_table(&ohosfwk_cmd_count);
+ at_cmd_add_moudle(ohosfwk_table, ohosfwk_cmd_count);
+#endif
+#ifdef SUPPORT_AT_APP
+ uint32_t app_cmd_count;
+ at_cmd_table_t *app_table = get_app_cmd_table(&app_cmd_count);
+ at_cmd_add_moudle(app_table, app_cmd_count);
+#endif
+#ifdef SUPPORT_AT_AUDIO
+ uint32_t audio_cmd_count;
+ at_cmd_table_t *audio_table = get_audio_cmd_table(&audio_cmd_count);
+ at_cmd_add_moudle(audio_table, audio_cmd_count);
+#endif
+#ifdef SUPPORT_AT_BT_MANAGER
+ uint32_t bt_manager_cmd_count;
+ at_cmd_table_t *bt_manager_table = get_bt_manager_cmd_table(&bt_manager_cmd_count);
+ at_cmd_add_moudle(bt_manager_table, bt_manager_cmd_count);
+#endif
+#ifdef SUPPORT_AT_MEDIA
+ uint32_t media_cmd_count;
+ at_cmd_table_t *media_table = get_media_cmd_table(&media_cmd_count);
+ at_cmd_add_moudle(media_table, media_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_PPG
+ uint32_t hx3695_cmd_count;
+ at_cmd_table_t *hx3695_table = get_ppg_cmd_table(&hx3695_cmd_count);
+ at_cmd_add_moudle(hx3695_table, hx3695_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_VIBRATOR
+ uint32_t vibrator_cmd_count;
+ at_cmd_table_t *vibrator_table = get_vibrator_cmd_table(&vibrator_cmd_count);
+ at_cmd_add_moudle(vibrator_table, vibrator_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_HX3507
+ uint32_t hx3507_cmd_count;
+ at_cmd_table_t *hx3507_table = get_hx3507_cmd_table(&hx3507_cmd_count);
+ at_cmd_add_moudle(hx3507_table, hx3507_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_BATTERY
+ uint32_t battery_cmd_count;
+ at_cmd_table_t *battery_table = get_battery_cmd_table(&battery_cmd_count);
+ at_cmd_add_moudle(battery_table, battery_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_CUSTOMUTILS
+ uint32_t custom_utils_cmd_count;
+ at_cmd_table_t *custom_utils_table = get_custom_utils_cmd_table(&custom_utils_cmd_count);
+ at_cmd_add_moudle(custom_utils_table, custom_utils_cmd_count);
+#endif
+#ifdef SUPPORT_AT_CAT1
+ uint32_t cat1_cmd_count;
+ at_cmd_table_t *cat1_table = get_cat1_cmd_table(&cat1_cmd_count);
+ at_cmd_add_moudle(cat1_table, cat1_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_PPP
+ uint32_t ppp_cmd_count;
+ at_cmd_table_t *ppp_table = get_ppp_cmd_table(&ppp_cmd_count);
+ at_cmd_add_moudle(ppp_table, ppp_cmd_count);
+#endif
+
+#ifdef SUPPORT_ZHIHUI_AI_OLD
+ uint32_t ai_old_cmd_count;
+ at_cmd_table_t *ai_old_table = get_ai_old_cmd_table(&ai_old_cmd_count);
+ at_cmd_add_moudle(ai_old_table, ai_old_cmd_count);
+#endif
+
+#ifdef SUPPORT_ZHIHUI_AI_NEW
+ uint32_t ai_new_cmd_count;
+ at_cmd_table_t *ai_new_table = get_ai_2_5_cmd_table(&ai_new_cmd_count);
+ at_cmd_add_moudle(ai_new_table, ai_new_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_LIS2DOC
+ uint32_t lis2doc_cmd_count;
+ at_cmd_table_t *lis2doc_table = get_lis2doc_cmd_table(&lis2doc_cmd_count);
+ at_cmd_add_moudle(lis2doc_table, lis2doc_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_CYWEE
+ uint32_t cywee_cmd_count;
+ at_cmd_table_t *cywee_table = get_cywee_cmd_table(&cywee_cmd_count);
+ at_cmd_add_moudle(cywee_table, cywee_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_MAG
+ uint32_t mag_cmd_count;
+ at_cmd_table_t *mag_table = get_mag_cmd_table(&mag_cmd_count);
+ at_cmd_add_moudle(mag_table, mag_cmd_count);
+#endif
+
+#ifdef SUPPORT_AT_RTCTEST
+ uint32_t rtc_cmd_count;
+ at_cmd_table_t *rtc_table = get_rtc_cmd_table(&rtc_cmd_count);
+ at_cmd_add_moudle(rtc_table, rtc_cmd_count);
+#endif
+#ifdef SUPPORT_AT_HX3508
+ uint32_t hx3508_cmd_count;
+ at_cmd_table_t *hx3508_table = get_hx3508_cmd_table(&hx3508_cmd_count);
+ at_cmd_add_moudle(hx3508_table, hx3508_cmd_count);
+#endif
+#ifdef SUPPORT_AT_LQBP002TA
+ uint32_t lqbp002ta_cmd_count;
+ at_cmd_table_t *lqbp002ta_table = get_lqbp002ta_cmd_table(&lqbp002ta_cmd_count);
+ at_cmd_add_moudle(lqbp002ta_table, lqbp002ta_cmd_count);
+#endif
+#ifdef SUPPORT_AT_CHARGE
+ uint32_t charge_cmd_count;
+ at_cmd_table_t *charge_table = get_charge_cmd_table(&charge_cmd_count);
+ at_cmd_add_moudle(charge_table, charge_cmd_count);
+#endif
+#ifdef SUPPORT_AT_CROWN
+ uint32_t crown_cmd_count;
+ at_cmd_table_t *crown_table = get_crown_cmd_table(&crown_cmd_count);
+ at_cmd_add_moudle(crown_table, crown_cmd_count);
+#endif
+#ifdef SUPPORT_AT_MIXO
+ uint32_t mixo_cmd_count;
+ at_cmd_table_t *mixo_table = get_mixo_cmd_table(&mixo_cmd_count);
+ at_cmd_add_moudle(mixo_table, mixo_cmd_count);
+#endif
+#ifdef SUPPORT_AT_GYRO
+ uint32_t gyro_cmd_count;
+ at_cmd_table_t *gyro_table = get_gyro_cmd_table(&gyro_cmd_count);
+ at_cmd_add_moudle(gyro_table, gyro_cmd_count);
+#endif
+#ifdef SUPPORT_AT_BP
+ uint32_t bp_cmd_count;
+ at_cmd_table_t *bp_table = get_bp_cmd_table(&bp_cmd_count);
+ at_cmd_add_moudle(bp_table, bp_cmd_count);
+#endif
+#ifdef SUPPORT_AT_LEINIAO_API
+ uint32_t leiniao_api_cmd_count;
+ at_cmd_table_t *leiniao_api_table = get_leiniao_api_cmd_table(&leiniao_api_cmd_count);
+ at_cmd_add_moudle(leiniao_api_table, leiniao_api_cmd_count);
+
+ uint32_t uapi_mqtt_at_cmd_count;
+ at_cmd_table_t *uapi_mqtt_at_table = get_uapi_mqtt_at_cmd_table(&uapi_mqtt_at_cmd_count);
+ at_cmd_add_moudle(uapi_mqtt_at_table, uapi_mqtt_at_cmd_count);
+#ifdef SUPPORT_LN_MQTT_SERVICE
+ uint32_t ln_mqtt_at_cmd_count;
+ at_cmd_table_t *ln_mqtt_at_table = get_ln_mqtt_at_cmd_table(&ln_mqtt_at_cmd_count);
+ at_cmd_add_moudle(ln_mqtt_at_table, ln_mqtt_at_cmd_count);
+#endif
+
+#endif
+
+#ifdef SUPPORT_ZHIHUI_AI_SERVICE
+ uint32_t ai_cmd_count;
+ at_cmd_table_t *ai_table = get_ai_cmd_table(&ai_cmd_count);
+ at_cmd_add_moudle(ai_table, ai_cmd_count);
+#endif
+
+#ifdef ENABLE_VAD_SERVER
+ uint32_t imsl_vad_cmd_count;
+ at_cmd_table_t *imsl_vad_table = get_imsl_vad_at_cmd_table(&imsl_vad_cmd_count);
+ at_cmd_add_moudle(imsl_vad_table, imsl_vad_cmd_count);
+#endif
+
+
+#ifdef SUPPORT_ZHIHUI_DMP
+ uint32_t dmp_api_cmd_count;
+ at_cmd_table_t *dmp_api_table = get_dmp_api_cmd_table(&dmp_api_cmd_count);
+ at_cmd_add_moudle(dmp_api_table, dmp_api_cmd_count);
+#endif
+
+// #ifdef SUPPORT_AT_AI_API
+// uint32_t ai_api_cmd_count;
+// at_cmd_table_t *ai_api_table = get_ai_api_cmd_table(&ai_api_cmd_count);
+// at_cmd_add_moudle(ai_api_table, ai_api_cmd_count);
+// #endif
+
+}
+
+#ifdef CONFIG_OTA_UPDATE_SUPPORT
+static void upg_putc(const char c)
+{
+ printf("%c", c);
+}
+#endif
+
+void service_init(void)
+{
+#if defined(FREERTOS_TEST)
+ // freertos demo test
+ extern int main_full(void);
+ (void)main_full();
+ for (;;) {
+ }
+#endif
+
+ /* dfx init step 1: log init */
+ log_init();
+ log_init_after_rtos();
+ log_uart_init_after_rtos();
+
+ cpu_utils_init();
+ hal_register_exception_dump_callback(log_exception_dump);
+ uapi_partition_init();
+ PRINT("partition init success"NEWLINE);
+
+#ifdef CONFIG_OTA_UPDATE_SUPPORT
+ upg_func_t upg_func = {0};
+ upg_func.malloc = malloc;
+ upg_func.free = free;
+ upg_func.serial_putc = upg_putc;
+ (void)uapi_upg_init(&upg_func);
+ PRINT("upg init success\r\n");
+#endif
+ crypto_drv_init();
+ uapi_nv_init();
+#ifdef SUPPORT_AT_BT_MANAGER
+ set_calibration_from_nv();
+#endif
+ /* dfx init step 2: dfx init */
+#ifdef HSO_SUPPORT
+ dfx_system_init();
+#endif
+ /* power manager init */
+ uapi_pm_init();
+#ifdef SUPPORT_POWER_MANAGER
+ uapi_power_display_init();
+#endif
+
+ register_at_service();
+}
# 'CYWEE_MAC_ACTIVE',
#'SUPPORT_HID_SERVICE',
# 'SUPPORT_BAIDU_MAP',
+ # 'SUPPORT_LN_MQTT_SERVICE',
'CFG_FLASH_SIZE=16',
'CONFIG_NORFLASH_SIZE=16',
'SINGLE_USER_PARTITION',
#cat1 相关配置
#有方需要开启 PPP
# "ppp",
+ # "mqtt_service",
#EG810 需要开启 cat1Service 和 cat1Test
"cat1Service",
#VAD 相关配置
"imsl",
"minimp3",
+ # "opus_frame_to_pcm",
# "CustomUIcomponentTool",
"nativeabilityfwk",
"custom_utils",
${ROOT_DIR}/kernel/dpal/device/include
${ROOT_DIR}/kernel/osal/include
${FREERTOSTOPDIR}/sys/dev/mmc
+ ${ROOT_DIR}/open_source/openharmony/third_party/lwip/lwip_adapter/liteos/src/include
)
aux_source_directory(${FS_PATH}/yaffs2/os_adapt/adapt_freertos PUBLIC_HEADER)
static void mqtt_connection_status_cb(void *arg, int status)
{
(void)arg;
- MQTT_DEBUG("Connection status callback: %d\n", status);
+ MQTT_ERROR("Connection status callback: %d\n", status);
// 更新连接状态码
g_mqtt_connection_status = status;
}
}
+/* OTA-发送设备信息到服务器:AT^LN_OTA_SEND_DEVICE_INFO */
+// static uint32_t ln_ota_send_device_info_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+// {
+// (void)para;
+// (void)paraLen;
+// (void)strCommonCmd;
+
+// printf("[LN][OTA_SEND_DEVICE_INFO]\n");
+
+// // 直接调用封装函数,使用默认URL(NULL表示使用默认URL)
+// int ret = ln_ota_send_device_info_json(NULL, NULL);
+// if (ret == 0) {
+// printf("+LN_OTA_SEND_DEVICE_INFO: OK\n");
+// return ERRCODE_SUCC;
+// } else {
+// printf("+LN_OTA_SEND_DEVICE_INFO: FAIL\n");
+// return ERRCODE_FAIL;
+// }
+// }
/* MQTT-初始化:AT^LN_MQTT_INIT */
static uint32_t uapi_mqtt_init_at(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
(void)paraLen;
(void)strCommonCmd;
- const char *defaultArgs[6] = {"01", "opus", "16000", "1", "16", "user/userdata/test.ogg"};
+ const char *defaultArgs[6] = {"01", "sbc", "16000", "1", "16", "user/userdata/test.sbc"};
int ret = AudioCaptureSample(6, defaultArgs);
LOS_Msleep(1000*10);
#include "opus_frame_to_pcm.h"
#include "ai_media.h"
-/* 双流接口开关:定义 USE_DUAL_STREAM_INTERFACE 则使用 old_Start_AIVoice 双流接口,否则使用 MQTT_StartRecord */
-/* 可在 CMakeLists.txt 或编译选项中定义,例如:-DUSE_DUAL_STREAM_INTERFACE=1 */
-#ifndef USE_DUAL_STREAM_INTERFACE
-#define USE_DUAL_STREAM_INTERFACE 0
-#endif
-
/* OGG 封装相关前向声明(不透明句柄,避免依赖 ogg.h) */
/* OGG 上下文句柄(不透明指针,实际类型在 ai_media_service_mqtt.cpp 中定义) */
typedef void* MqttOggContextHandle;
#define OGG_MAX_OUT_OF_ORDER_COUNT 5 // 最大连续错序次数,超过后跳过一包
#define AUDIO_SEND_MAX_DATA_SIZE 0x800 // 最大音频数据大小(与 LN_MQTT_RECORD_MAX_FRAME 一致)
+/* 音频编码类型:入队时 data 的格式 */
+#define AUDIO_SEND_ENCODING_OPUS 0 // 已是 Opus,直接发送
+#define AUDIO_SEND_ENCODING_PCM 1 // PCM,发送前用 opus_pcm_to_frame_encode_packet 编码为 Opus
+
+/* PCM 编码默认参数(encoding==PCM 时使用):输入为 16kHz 单声道、16-bit 小端 */
+#define AUDIO_SEND_PCM_SAMPLE_RATE 16000 /* 采样率 16kHz */
+#define AUDIO_SEND_PCM_CHANNELS 1 /* 单声道 */
+#define AUDIO_SEND_PCM_BITRATE 64000
+#define AUDIO_SEND_PCM_APPLICATION 2049 /* Opus: OPUS_APPLICATION_AUDIO,必须为 2048/2049/2051 之一 */
+#define AUDIO_SEND_PCM_FRAME_MS 60 // 每帧 60ms,切割固定长度再编码
+/* 60ms 对应字节数:sample_rate * frame_ms/1000 * channels * 2(bytes/sample) */
+#define AUDIO_SEND_PCM_FRAME_BYTES ((uint32_t)((AUDIO_SEND_PCM_SAMPLE_RATE) * (AUDIO_SEND_PCM_FRAME_MS) / 1000 * (AUDIO_SEND_PCM_CHANNELS) * 2))
+#define AUDIO_SEND_PCM_FRAME_SAMPLES ((int)((AUDIO_SEND_PCM_SAMPLE_RATE) * (AUDIO_SEND_PCM_FRAME_MS) / 1000))
+/* 动态分配容量:帧数可调以增大缓存(约 6s @ 60ms/帧) */
+#define AUDIO_SEND_PCM_CACHE_ALLOC_FRAMES 100
+#define AUDIO_SEND_PCM_CACHE_ALLOC_SIZE ((AUDIO_SEND_PCM_CACHE_ALLOC_FRAMES) * (AUDIO_SEND_PCM_FRAME_BYTES) + (AUDIO_SEND_MAX_DATA_SIZE))
+
+/* PCM 发送缓存:动态分配,新数据追加,满 60ms 切割编码,余量保留 */
+static uint8_t *g_pcm_send_cache = NULL;
+static uint32_t g_pcm_send_cache_capacity = 0; /* 已分配容量(字节) */
+static uint32_t g_pcm_send_cache_size = 0; /* 当前有效数据长度 */
+
/* 音频数据消息结构体 */
typedef struct {
uint8_t *data; // 音频数据指针(动态分配)
- uint32_t size; // 数据大小
+ uint32_t size; // 数据大小(字节)
+ uint8_t encoding; // 0=Opus,1=PCM(发送前编码为 Opus)
} audio_send_msg_t;
static unsigned long g_audio_send_queue = 0xFFFFFFFF; // 消息队列句柄
}
#endif /* USE_DUAL_STREAM_INTERFACE */
+/* 接收线程内固定时间间隔(秒)后重新创建 socket,0 表示不按时间重建 */
+#define UDP_RECV_RECREATE_INTERVAL_SEC 0
+
+/**
+ * @brief 仅创建并配置 UDP socket(不启动线程),供创建与接收线程内重建复用
+ * @return socket fd,失败返回 -1
+ */
+static int ln_udp_create_socket_fd_only(void)
+{
+ ln_mqtt_udp_info_t udp_info;
+ if (ln_mqtt_api_get_udp_info(&udp_info) != 0 || !udp_info.valid) {
+ return -1;
+ }
+ int fd = lwip_socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return -1;
+ }
+ int opt = 1;
+ lwip_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ return fd;
+}
+
/**
* @brief UDP接收线程
*/
uint8_t recv_buffer[UDP_RECV_BUFFER_SIZE];
struct sockaddr_in server_addr;
socklen_t addr_len = sizeof(server_addr);
-
+ uint32_t last_recreate_tick = 0;
+ uint32_t recreate_interval_ticks = 0;
+
printf("[LN_UDP] Receive thread started\n");
-
+
// 获取服务器地址信息
ln_mqtt_udp_info_t udp_info;
if (ln_mqtt_api_get_udp_info(&udp_info) != 0 || !udp_info.valid) {
g_udp_thread_running = false;
return;
}
-
+
// 设置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = lwip_htons(udp_info.port);
server_addr.sin_addr.s_addr = inet_addr(udp_info.server);
-
- // printf("[LN_UDP] Ready to receive UDP packets from %s:%d\n", udp_info.server, udp_info.port);
-
+ if (UDP_RECV_RECREATE_INTERVAL_SEC > 0) {
+ recreate_interval_ticks = (uint32_t)osKernelGetTickFreq() * UDP_RECV_RECREATE_INTERVAL_SEC;
+ last_recreate_tick = osKernelGetTickCount();
+ }
+
while (g_udp_thread_running && g_udp_socket >= 0) {
+ printf("g_udp_thread_running %d g_udp_socket %d\r\n",g_udp_thread_running,g_udp_socket);
+ // 固定时间间隔到达则重新创建 socket
+ if (UDP_RECV_RECREATE_INTERVAL_SEC > 0 && recreate_interval_ticks > 0) {
+ uint32_t now = osKernelGetTickCount();
+ if ((now - last_recreate_tick) >= recreate_interval_ticks) {
+ printf("[LN_UDP] Recreate interval reached (%u s), recreating socket\n", (unsigned)UDP_RECV_RECREATE_INTERVAL_SEC);
+ lwip_close(g_udp_socket);
+ g_udp_socket = ln_udp_create_socket_fd_only();
+ if (g_udp_socket < 0) {
+ printf("[LN_UDP] Failed to recreate socket: %s\n", strerror(errno));
+ break;
+ }
+ /* 重新获取 UDP 地址信息(服务端地址/端口可能变化) */
+ if (ln_mqtt_api_get_udp_info(&udp_info) != 0 || !udp_info.valid) {
+ printf("[LN_UDP] UDP info not available after recreate, keep last address\n");
+ } else {
+ memset(&server_addr, 0, sizeof(server_addr));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = lwip_htons(udp_info.port);
+ server_addr.sin_addr.s_addr = inet_addr(udp_info.server);
+ addr_len = sizeof(server_addr);
+ }
+ last_recreate_tick = osKernelGetTickCount();
+ }
+ }
+
// 接收UDP数据(阻塞,超时1秒)
fd_set read_fds;
struct timeval timeout;
-
+
FD_ZERO(&read_fds);
FD_SET(g_udp_socket, &read_fds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
-
+
int select_ret = lwip_select(g_udp_socket + 1, &read_fds, NULL, NULL, &timeout);
if (select_ret > 0 && FD_ISSET(g_udp_socket, &read_fds)) {
// 有数据可读
ssize_t recv_len = lwip_recvfrom(g_udp_socket, recv_buffer, sizeof(recv_buffer) - 1, 0,
(struct sockaddr *)&server_addr, &addr_len);
-
+
if (recv_len > 0) {
- printf("[LN_UDP] Received %d bytes\r\n",
+ printf("[LN_UDP] Received %d bytes\r\n",
(int)recv_len
);
-
+
// 处理接收到的数据(解包、解密)
ln_udp_process_received_data(recv_buffer, (uint16_t)recv_len);
-
+
} else if (recv_len == 0) {
printf("[LN_UDP] Connection closed by peer\n");
break;
}
}
} else if (select_ret < 0) {
+ printf("select_ret %d\r\n",select_ret);
if (errno != EINTR) {
printf("[LN_UDP] Select error: %s\n", strerror(errno));
break;
}
// select_ret == 0 表示超时,继续循环
}
-
+
printf("[LN_UDP] Receive thread exited\n");
g_udp_thread_running = false;
}
}
printf("[LN_UDP] Creating UDP socket for server: %s:%d\n", udp_info.server, udp_info.port);
-
+
// 如果socket已存在,先关闭
if (g_udp_socket >= 0) {
printf("[LN_UDP] Closing existing UDP socket\n");
ln_udp_close_socket();
}
-
- // 创建UDP套接字
- g_udp_socket = lwip_socket(AF_INET, SOCK_DGRAM, 0);
+
+ // 创建UDP套接字(复用仅创建 fd 的逻辑)
+ g_udp_socket = ln_udp_create_socket_fd_only();
if (g_udp_socket < 0) {
printf("[LN_UDP] Failed to create UDP socket: %s\n", strerror(errno));
return -1;
}
-
- // 设置socket选项(允许地址重用)
- int opt = 1;
- lwip_setsockopt(g_udp_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
- // 设置为非阻塞模式(可选,用于select超时)
- // int flags = lwip_fcntl(g_udp_socket, F_GETFL, 0);
- // lwip_fcntl(g_udp_socket, F_SETFL, flags | O_NONBLOCK);
-
+
printf("[LN_UDP] UDP socket created successfully, fd=%d\n", g_udp_socket);
// 创建接收线程
}
}
+/**
+ * @brief 发送单帧音频数据(打包/加密 + 发送)
+ * @note 复用原有 ln_udp_pack_audio_data 加密逻辑
+ * @return 0 成功,-1 失败
+ */
+static int ln_udp_send_audio_frame(int sock, const uint8_t *audio_data, uint32_t audio_size)
+{
+ if (audio_data == NULL || audio_size == 0 || audio_size > AUDIO_SEND_MAX_DATA_SIZE) {
+ return -1;
+ }
+
+ // 打包(加密+UDP头)
+ uint8_t send_buf[UDP_PACKET_HEADER_SIZE + AUDIO_SEND_MAX_DATA_SIZE];
+ uint16_t out_len = 0;
+ if (ln_udp_pack_audio_data(audio_data, (uint16_t)audio_size, send_buf,
+ (uint16_t)sizeof(send_buf), &out_len) != 0) {
+ printf("[LN_UDP] Failed to pack audio frame\n");
+ return -1;
+ }
+
+ // 获取UDP信息(用于发送)
+ ln_mqtt_udp_info_t udp_info;
+ if (ln_mqtt_api_get_udp_info(&udp_info) != 0 || !udp_info.valid) {
+ printf("[LN_UDP] UDP info not available, drop audio frame\n");
+ return -1;
+ }
+
+ // 发送到服务器
+ struct sockaddr_in server_addr;
+ memset(&server_addr, 0, sizeof(server_addr));
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = lwip_htons(udp_info.port);
+ server_addr.sin_addr.s_addr = inet_addr(udp_info.server);
+
+ ssize_t sent = lwip_sendto(sock, send_buf, out_len, 0,
+ (struct sockaddr *)&server_addr, sizeof(server_addr));
+ if (sent < 0) {
+ printf("[LN_UDP] UDP sendto failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
/**
* @brief 音频数据发送线程
*/
continue;
}
- // 打包(加密+UDP头)
- uint8_t send_buf[UDP_PACKET_HEADER_SIZE + AUDIO_SEND_MAX_DATA_SIZE];
- uint16_t out_len = 0;
- if (ln_udp_pack_audio_data(msg.data, (uint16_t)msg.size, send_buf,
- (uint16_t)sizeof(send_buf), &out_len) != 0) {
- printf("[LN_UDP] Failed to pack audio frame\n");
+ const uint8_t *send_data = msg.data;
+ uint32_t send_size = msg.size;
+ if (msg.encoding == AUDIO_SEND_ENCODING_PCM) {
+ /* PCM:追加到缓存,按 60ms 切割编码,余量保留 */
+ if (g_pcm_send_cache == NULL) {
+ printf("[LN_UDP] PCM cache not allocated, drop %u bytes\n", msg.size);
+ free(msg.data);
+ continue;
+ }
+ while (g_pcm_send_cache_size + msg.size > g_pcm_send_cache_capacity &&
+ g_pcm_send_cache_size >= AUDIO_SEND_PCM_FRAME_BYTES) {
+ /* 缓存满时丢弃最旧一帧,避免持续溢出 */
+ g_pcm_send_cache_size -= AUDIO_SEND_PCM_FRAME_BYTES;
+ memmove(g_pcm_send_cache, g_pcm_send_cache + AUDIO_SEND_PCM_FRAME_BYTES, g_pcm_send_cache_size);
+ }
+ if (g_pcm_send_cache_size + msg.size > g_pcm_send_cache_capacity) {
+ printf("[LN_UDP] PCM cache full, drop %u bytes (cache=%u, cap=%u)\n", msg.size, g_pcm_send_cache_size, g_pcm_send_cache_capacity);
+ free(msg.data);
+ continue;
+ }
+ memcpy(g_pcm_send_cache + g_pcm_send_cache_size, msg.data, msg.size);
+ g_pcm_send_cache_size += msg.size;
free(msg.data);
+ msg.data = NULL;
+
+ /* 每次取 60ms 固定长度编码并发送,多余数据留在缓存 */
+ uint8_t opus_buf[1500];
+
+ while (g_pcm_send_cache_size >= AUDIO_SEND_PCM_FRAME_BYTES) {
+ int encoded_len = 0;
+ printf("[LN_UDP] PCM send cache size: %d\n", g_pcm_send_cache_size);
+ for (int i = 0; i < AUDIO_SEND_PCM_FRAME_BYTES; i++) {
+ printf("%02x ", g_pcm_send_cache[i]);
+ }
+ printf("\n");
+
+ if (opus_pcm_to_frame_encode_packet(
+ (const short *)g_pcm_send_cache, AUDIO_SEND_PCM_FRAME_SAMPLES,
+ AUDIO_SEND_PCM_SAMPLE_RATE, AUDIO_SEND_PCM_CHANNELS,
+ AUDIO_SEND_PCM_BITRATE, AUDIO_SEND_PCM_APPLICATION,
+ opus_buf, (int)sizeof(opus_buf), &encoded_len) != 0) {
+ printf("[LN_UDP] PCM to Opus encode failed, drop 60ms frame\n");
+ break;
+ }
+ printf("[LN_UDP] Opus encoded len: %d\n", encoded_len);
+ printf("[LN_UDP] Opus encoded data: ");
+ for (int i = 0; i < encoded_len; i++) {
+ printf("%02x ", opus_buf[i]);
+ }
+ printf("\n");
+ if (ln_udp_send_audio_frame(sock, opus_buf, (uint32_t)encoded_len) != 0) {
+ break;
+ }
+ /* 移除已编码的一帧,保留余量 */
+ g_pcm_send_cache_size -= AUDIO_SEND_PCM_FRAME_BYTES;
+ memmove(g_pcm_send_cache, g_pcm_send_cache + AUDIO_SEND_PCM_FRAME_BYTES, g_pcm_send_cache_size);
+ }
continue;
}
- // 获取UDP信息(用于发送)
- ln_mqtt_udp_info_t udp_info;
- if (ln_mqtt_api_get_udp_info(&udp_info) != 0 || !udp_info.valid) {
- printf("[LN_UDP] UDP info not available, drop audio frame\n");
+ (void)send_data;
+ if (ln_udp_send_audio_frame(sock, send_data, send_size) != 0) {
free(msg.data);
continue;
}
- // 发送到服务器
- struct sockaddr_in server_addr;
- memset(&server_addr, 0, sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = lwip_htons(udp_info.port);
- server_addr.sin_addr.s_addr = inet_addr(udp_info.server);
-
- ssize_t sent = lwip_sendto(sock, send_buf, out_len, 0,
- (struct sockaddr *)&server_addr, sizeof(server_addr));
- if (sent < 0) {
- printf("[LN_UDP] UDP sendto failed: %s\n", strerror(errno));
- }
-
// 释放音频数据内存
free(msg.data);
msg.data = NULL;
*/
int ln_udp_audio_send_init(void)
{
+ // 动态分配 PCM 发送缓存(若未分配或需扩容可在此统一申请)
+ if (g_pcm_send_cache == NULL) {
+ g_pcm_send_cache = (uint8_t *)malloc(AUDIO_SEND_PCM_CACHE_ALLOC_SIZE);
+ if (g_pcm_send_cache == NULL) {
+ printf("[LN_UDP] Failed to allocate PCM send cache (%u bytes)\n", (unsigned)AUDIO_SEND_PCM_CACHE_ALLOC_SIZE);
+ return -1;
+ }
+ g_pcm_send_cache_capacity = AUDIO_SEND_PCM_CACHE_ALLOC_SIZE;
+ g_pcm_send_cache_size = 0;
+ printf("[LN_UDP] PCM send cache allocated: %u bytes\n", g_pcm_send_cache_capacity);
+ }
+
// 创建消息队列
create_audio_send_queue();
if (g_audio_send_queue == 0xFFFFFFFF) {
printf("[LN_UDP] Failed to create audio send queue\n");
+ if (g_pcm_send_cache != NULL) {
+ free(g_pcm_send_cache);
+ g_pcm_send_cache = NULL;
+ g_pcm_send_cache_capacity = 0;
+ }
return -1;
}
app_task_definition_ext_t send_task = {
.attr = {
.name = "ln_udp_audio_send",
- .stack_size = 0x2000,
+ .stack_size = 0x8000,
.priority = osPriorityNormal
},
.func = ln_udp_audio_send_thread,
*/
void ln_udp_audio_send_deinit(void)
{
+ g_pcm_send_cache_size = 0;
+ g_pcm_send_cache_capacity = 0;
+ if (g_pcm_send_cache != NULL) {
+ free(g_pcm_send_cache);
+ g_pcm_send_cache = NULL;
+ }
// 停止发送线程
if (g_audio_send_thread_running) {
printf("[LN_UDP] Stopping audio send thread\n");
audio_send_msg_t wake_msg = {0};
wake_msg.data = NULL;
wake_msg.size = 0;
+ wake_msg.encoding = AUDIO_SEND_ENCODING_OPUS;
osal_msg_queue_write_copy(g_audio_send_queue, (void *)&wake_msg, sizeof(audio_send_msg_t), 0);
// 等待线程退出(最多等待2秒)
* @param size 音频数据大小
* @return 0 成功,-1 失败
* @note 函数内部会动态分配内存并复制数据,发送线程负责释放内存
+ * @param encoding AUDIO_SEND_ENCODING_OPUS(0)=已是 Opus;AUDIO_SEND_ENCODING_PCM(1)=PCM,发送前编码为 Opus
*/
-int ln_udp_audio_send_enqueue(const uint8_t *data, uint32_t size)
+int ln_udp_audio_send_enqueue(const uint8_t *data, uint32_t size, uint8_t encoding)
{
if (!data || size == 0 || size > AUDIO_SEND_MAX_DATA_SIZE) {
printf("[LN_UDP] Invalid parameters for audio send enqueue\n");
audio_send_msg_t msg;
msg.data = data_copy;
msg.size = size;
+ msg.encoding = (encoding != AUDIO_SEND_ENCODING_PCM) ? AUDIO_SEND_ENCODING_OPUS : AUDIO_SEND_ENCODING_PCM;
// 写入队列(非阻塞,如果队列满则丢弃并释放内存)
int32_t ret = osal_msg_queue_write_copy(g_audio_send_queue, (void *)&msg, sizeof(audio_send_msg_t), 0);
#include "lwip/sockets.h"
#include "lwip/inet.h"
#include "lwip/netdb.h"
+#include <time.h>
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+#include "vad_server.h"
+#include "errcode.h"
+#include "cmsis_os2.h"
+#endif
#define LN_MQTT_SEND_TOPIC "device-server-enhanced"
+/* 测试性录音数据保存到文件:1=启用,0=禁用。启用后每次开始录音创建新文件,停止时关闭。 */
+#ifndef LN_MQTT_RECORD_SAVE_TO_FILE_TEST
+#define LN_MQTT_RECORD_SAVE_TO_FILE_TEST 1
+#endif
+
/* MQTT API 全局状态 */
static bool g_ln_mqtt_service_started = false;
/* UDP信息全局变量 */
static ln_mqtt_udp_info_t g_udp_info = {0};
+static uint8_t g_audio_format_input = SBC;
/* hello 消息中的 session_id(用于后续 listen 控制消息) */
static char g_ln_mqtt_session_id[64] = {0};
/* 音频初始化状态标志位 */
static volatile bool g_mqtt_audio_initialized = false;
+/* 消息处理回调函数(参考 ln_ws_start,可为 NULL) */
+static ws_message_callback_t_ln g_mqtt_message_callback = NULL;
+
int ln_mqtt_api_send_hello(void);
// --- MQTT 录音(来自 ai_media_service_mqtt.cpp,无对应头文件时在此声明) ---
uint8_t *buffer, uint16_t buffer_size, uint16_t *out_len);
extern int ln_udp_audio_send_init(void);
extern void ln_udp_audio_send_deinit(void);
-extern int ln_udp_audio_send_enqueue(const uint8_t *data, uint32_t size);
+extern int ln_udp_audio_send_enqueue(const uint8_t *data, uint32_t size, uint8_t encoding);
#define LN_UDP_PACKET_HEADER_SIZE 16
#define LN_MQTT_RECORD_MAX_FRAME 0x800
-#define LN_MQTT_RECORD_BATCH_SIZE 5 // 每5包数据合并后入队
+#define LN_MQTT_RECORD_BATCH_SIZE 2 // 每5包数据合并后入队
/* 双流接口开关:定义 USE_DUAL_STREAM_INTERFACE 则使用 old_Start_AIVoice 双流接口,否则使用 MQTT_StartRecord */
/* 可在 CMakeLists.txt 或编译选项中定义,例如:-DUSE_DUAL_STREAM_INTERFACE=1 */
static volatile bool g_recording_upload_started = false;
#endif /* USE_DUAL_STREAM_INTERFACE */
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+/* VAD 服务器状态标志位(参考 ln_api_websocket.c) */
+static volatile bool g_mqtt_vad_server_enabled = false;
+static volatile bool g_mqtt_vad_server_initialized = false;
+/* VAD 冷却时间(参考 ln_ws,避免频繁触发对话) */
+static uint32_t g_mqtt_vad_cooldown_start_tick = 0;
+static volatile bool g_mqtt_vad_cooldown_active = false;
+static uint32_t g_mqtt_vad_cooldown_duration_ms = 3000; /* 10秒 */
+
+static bool ln_mqtt_is_vad_cooldown_active(void);
+static void ln_mqtt_start_vad_cooldown(void);
+#endif /* ENABLE_VAD_SERVER */
+
+static void ln_mqtt_record_data_cb(const uint8_t* data, uint32_t size, void* userData);
+
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+/**
+ * @brief 检查 VAD 冷却是否激活(参考 ln_ws_is_vad_cooldown_active)
+ */
+static bool ln_mqtt_is_vad_cooldown_active(void)
+{
+ if (!g_mqtt_vad_cooldown_active) {
+ return false;
+ }
+ uint32_t current_tick = osKernelGetTickCount();
+ uint32_t elapsed_ms = current_tick - g_mqtt_vad_cooldown_start_tick;
+ if (elapsed_ms >= g_mqtt_vad_cooldown_duration_ms) {
+ g_mqtt_vad_cooldown_active = false;
+ printf("[LN_MQTT_API] VAD cooldown period ended\n");
+ return false;
+ }
+ return true;
+}
+
+/**
+ * @brief 开始 VAD 冷却计时(参考 ln_ws_start_vad_cooldown)
+ */
+static void ln_mqtt_start_vad_cooldown(void)
+{
+ g_mqtt_vad_cooldown_start_tick = osKernelGetTickCount();
+ g_mqtt_vad_cooldown_active = true;
+ printf("[LN_MQTT_API] VAD cooldown started, duration: %u ms\n", g_mqtt_vad_cooldown_duration_ms);
+}
+
+/**
+ * @brief VAD 状态回调(参考 vad_status_callback_ln_ws,含冷却机制)
+ * @param status 1=检测到说话开始,2=检测到说话结束
+ */
+static void vad_status_callback_ln_mqtt(int status)
+{
+ printf("[LN_MQTT_API] VAD status callback: %d\n", status);
+ if (!g_mqtt_vad_server_enabled) {
+ return;
+ }
+ if (status == 1) {
+ if (ln_mqtt_is_vad_cooldown_active()) {
+ printf("[LN_MQTT_API] VAD cooldown active, ignoring start request\n");
+ return;
+ }
+ (void)ln_mqtt_api_send_listen_state(true);
+ } else if (status == 2) {
+ (void)ln_mqtt_api_send_listen_state(false);
+ /* 对话结束后启动冷却,避免频繁触发 */
+ ln_mqtt_start_vad_cooldown();
+ }
+}
+#endif /* ENABLE_VAD_SERVER */
+
+/**
+ * @brief MQTT 音频辅助初始化(参考 ln_ws_audio_init,独立可调用)
+ * @note 仅在 USE_DUAL_STREAM_INTERFACE 时初始化 old_Start_AIVoice 双流接口
+ */
+void ln_mqtt_audio_init(void)
+{
+#if USE_DUAL_STREAM_INTERFACE
+ if (g_mqtt_audio_initialized) {
+ printf("[LN_MQTT_API] Audio already initialized, skipping duplicate initialization\n");
+ return;
+ }
+
+ printf("[LN_MQTT_API] Initializing audio with old_Start_AIVoice dual stream interface\n");
+
+ if (AI_IsVoiceServiceRunning()) {
+ printf("[LN_MQTT_API] AI voice service already running, stopping it first\n");
+ StopAIVoice();
+ }
+
+ AIVoiceAudioParams inputParams = {
+ .audioFormat =g_audio_format_input ,
+ .channelCount = 1,
+ .sampleRate = 16000
+ };
+
+ AIVoiceAudioParams outputParams = {
+ .audioFormat = PCM,
+ .channelCount = 1,
+ .sampleRate = 16000
+ };
+
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+ AIVoiceAudioParams audioParams_in_vad = {
+ .audioFormat = PCM,
+ .channelCount = 1,
+ .sampleRate = 16000
+ };
+#endif
+
+ int32_t start_ret = old_Start_AIVoice(
+ (AIVoiceDataCallback)ln_mqtt_record_data_cb,
+ NULL,
+ &inputParams,
+ &outputParams,
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+ NULL, /* VAD 上行流(PCM) */
+#else
+ NULL, /* 第二个上行流参数(NULL 表示不启用双流) */
+#endif
+ false
+ );
+
+ if (start_ret != 0) {
+ printf("[LN_MQTT_API] WARNING: old_Start_AIVoice failed: %d\n", (int)start_ret);
+ return;
+ }
+
+ g_mqtt_audio_initialized = true;
+ printf("[LN_MQTT_API] old_Start_AIVoice initialized successfully (SBC, 16kHz, mono)\n");
+
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+ /* 初始化 VAD 服务器(参考 ln_api_websocket.c ln_ws_audio_init) */
+ g_mqtt_vad_server_enabled = true;
+ if (!g_mqtt_vad_server_initialized) {
+ printf("[LN_MQTT_API] Initializing VAD server...\n");
+ errcode_t ret = vad_server_init(vad_status_callback_ln_mqtt);
+ if (ret == ERRCODE_SUCC) {
+ g_mqtt_vad_server_initialized = true;
+ printf("[LN_MQTT_API] VAD server initialized successfully\n");
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_VAD_INITIALIZED);
+ }
+ } else {
+ printf("[LN_MQTT_API] Failed to initialize VAD server: %d\n", (int)ret);
+ }
+ }
+#endif /* ENABLE_VAD_SERVER */
+
+ #ifdef SUPPORT_CAT1_SERVICE
+ cat1_api_keep_wakeup(1);
+ cat1_api_wakeup_cat1(1);
+
+ #endif
+ uapi_cat1_add_cat1_vote();
+
+#else
+ (void)0; /* 非双流模式使用 MQTT_StartRecord,无需预初始化 */
+#endif /* USE_DUAL_STREAM_INTERFACE */
+}
+
+/**
+ * @brief MQTT 音频辅助反初始化(参考 ln_ws_audio_deinit)
+ */
+void ln_mqtt_audio_deinit(void)
+{
+#if USE_DUAL_STREAM_INTERFACE
+ if (!g_mqtt_audio_initialized) {
+ return;
+ }
+
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER
+ if (g_mqtt_vad_server_initialized) {
+ printf("[LN_MQTT_API] Deinitializing VAD server...\n");
+ errcode_t ret = vad_server_deinit();
+ if (ret == ERRCODE_SUCC) {
+ g_mqtt_vad_server_initialized = false;
+ printf("[LN_MQTT_API] VAD server deinitialized successfully\n");
+ } else {
+ printf("[LN_MQTT_API] Failed to deinitialize VAD server: %d\n", (int)ret);
+ }
+ }
+ g_mqtt_vad_server_enabled = false;
+#endif /* ENABLE_VAD_SERVER */
+
+ g_recording_upload_started = false;
+ if (AI_IsVoiceServiceRunning()) {
+ (void)StopAIVoice();
+ printf("[LN_MQTT_API] AI voice service stopped\n");
+ }
+ g_mqtt_audio_initialized = false;
+ printf("[LN_MQTT_API] Audio deinitialized\n");
+
+ #ifdef SUPPORT_CAT1_SERVICE
+ cat1_api_keep_wakeup(0);
+ cat1_api_wakeup_cat1(0);
+
+ #endif
+ uapi_cat1_remove_cat1_vote();
+#else
+ (void)0;
+#endif /* USE_DUAL_STREAM_INTERFACE */
+}
+
+/**
+ * @brief 获取 MQTT 音频初始化状态
+ */
+bool ln_mqtt_is_audio_initialized(void)
+{
+ return g_mqtt_audio_initialized;
+}
+
+#if LN_MQTT_RECORD_SAVE_TO_FILE_TEST
+static FILE *g_record_test_file = NULL;
+
+static void ln_mqtt_record_test_file_open(void)
+{
+ if (g_record_test_file != NULL) {
+ return; /* 已打开 */
+ }
+ time_t now = time(NULL);
+ struct tm *tm_info = (now >= 0) ? localtime(&now) : NULL;
+ char filename[96];
+ if (tm_info) {
+ snprintf(filename, sizeof(filename), "/user/userdata/ln_mqtt_record_%04d%02d%02d_%02d%02d%02d.sbc",
+ tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
+ tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);
+ } else {
+ snprintf(filename, sizeof(filename), "/user/userdata/ln_mqtt_record_test.raw");
+ }
+ g_record_test_file = fopen(filename, "wb");
+ if (g_record_test_file) {
+ printf("[LN_MQTT_API] Test save file opened: %s\n", filename);
+ } else {
+ printf("[LN_MQTT_API] Failed to open test save file: %s\n", filename);
+ }
+}
+
+static void ln_mqtt_record_test_file_close(void)
+{
+ if (g_record_test_file) {
+ fclose(g_record_test_file);
+ g_record_test_file = NULL;
+ printf("[LN_MQTT_API] Test save file closed\n");
+ }
+}
+#endif /* LN_MQTT_RECORD_SAVE_TO_FILE_TEST */
+
static void ln_mqtt_record_data_cb(const uint8_t* data, uint32_t size, void* userData)
{
(void)userData;
return;
}
+#if defined(ENABLE_VAD_SERVER) && ENABLE_VAD_SERVER && USE_DUAL_STREAM_INTERFACE
+ /* VAD 音频送入(须在 early return 之前,VAD 需持续收流以检测唤醒) */
+ if (g_mqtt_vad_server_enabled && g_mqtt_vad_server_initialized && vad_server_is_running() ) {
+ if(g_audio_format_input == PCM)
+ {
+ // printf("vad_server_send_audio size %d\r\n",size);
+ (void)vad_server_send_audio(VAD_AUDIO_FORMAT_PCM, data, size, false);
+ }
+ else if(AI_GetSecondStreamInStatus())
+ {
+ uint8_t *pcm_data=(uint8_t *)malloc(1024*3);
+ if(pcm_data)
+ {
+ uint32_t len=1024*3;
+ AI_SecondStreamInObtainBuffer(pcm_data, &len);
+ printf("vad_server_send_audio size %d\r\n",len);
+ (void)vad_server_send_audio(VAD_AUDIO_FORMAT_PCM, pcm_data, len, false);
+ free(pcm_data);
+ }
+ printf("vad_server_send_audio size %d\r\n",size);
+ (void)vad_server_send_audio(VAD_AUDIO_FORMAT_PCM, data, size, false);
+ }
+
+ }
+#endif /* ENABLE_VAD_SERVER && USE_DUAL_STREAM_INTERFACE */
+
#if USE_DUAL_STREAM_INTERFACE
- // 如果录音上传未开始,只缓存数据,不处理上传
+ /* 如果录音上传未开始,只做 VAD,不处理上传 */
if (!g_recording_upload_started) {
- // 可以在这里缓存数据,等待开始标志位设置后再处理
- // 目前先直接返回,不处理数据
return;
}
#endif /* USE_DUAL_STREAM_INTERFACE */
printf("ln_mqtt_record_data_cb size %d\r\n",size);
+#if LN_MQTT_RECORD_SAVE_TO_FILE_TEST
+ /* 测试性保存到文件:首次写入时打开,之后追加 */
+ if (g_record_test_file == NULL) {
+ ln_mqtt_record_test_file_open();
+ }
+ if (g_record_test_file != NULL && size > 0) {
+ size_t n = fwrite(data, 1, (size_t)size, g_record_test_file);
+ if (n != (size_t)size) {
+ printf("[LN_MQTT_API] Test file write incomplete: %zu/%u\n", n, (unsigned)size);
+ }
+ }
+#endif /* LN_MQTT_RECORD_SAVE_TO_FILE_TEST */
+
+#ifdef USE_RECORD_CACHE
// 如果缓冲区未分配,先分配
if (g_record_cache.buffer == NULL) {
uint32_t initial_size = LN_MQTT_RECORD_MAX_FRAME * LN_MQTT_RECORD_BATCH_SIZE;
g_record_cache.current_size, size, g_record_cache.buffer_size);
// 如果缓存已满,强制刷新当前缓存
if (g_record_cache.current_size > 0) {
- if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size) != 0) {
+ if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size, AUDIO_SEND_ENCODING_OPUS) != 0) {
printf("[LN_MQTT_API] Failed to enqueue cached audio data\n");
}
g_record_cache.current_size = 0;
// 如果累积到5包,将缓存数据入队
if (g_record_cache.packet_count >= LN_MQTT_RECORD_BATCH_SIZE) {
- if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size) != 0) {
+ if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size, AUDIO_SEND_ENCODING_OPUS) != 0)
+ {
printf("[LN_MQTT_API] Failed to enqueue batched audio data, drop frame\n");
} else {
printf("[LN_MQTT_API] Enqueued %u packets, total size: %u bytes\n",
g_record_cache.current_size = 0;
g_record_cache.packet_count = 0;
}
-
- msleep(10);
+#else
+ if (ln_udp_audio_send_enqueue(data, size, AUDIO_SEND_ENCODING_OPUS) != 0) {
+ printf("[LN_MQTT_API] Failed to enqueue audio data, drop frame\n");
+ } else {
+ printf("[LN_MQTT_API] Enqueued %u bytes of audio data\n", size);
+ }
+#endif
+#if USE_DUAL_STREAM_INTERFACE
+ msleep(50);
+#endif
}
/**
} else {
printf("[LN_MQTT_API] No UDP information in hello message\n");
}
+
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_CONNECTED);
+ }
cJSON_Delete(root);
return 0;
}
else
{
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_DISCONNECTED);
+ }
extern void ln_udp_close_socket(void);
ln_udp_close_socket();
}
/**
* @brief 启动MQTT服务(启动线程、自动连接等)
+ * @param callback 消息处理回调函数,参考 ln_ws_start,可为 NULL
* @return 0 成功,-1 失败
*/
-int ln_mqtt_api_start_service(void)
+int ln_mqtt_api_start_service(ws_message_callback_t_ln callback)
{
if (g_ln_mqtt_service_started) {
WEARABLE_LOGW(WEARABLE_LOG_MODULE_APP, "[LN_MQTT_API] Service already started");
return 0;
}
+
+ g_mqtt_message_callback = callback;
+ if (callback != NULL) {
+ printf("[LN_MQTT_API] Message callback registered\n");
+ }
printf("[LN_MQTT_API] Starting MQTT service\n");
printf("[LN_MQTT_API] WARNING: Failed to init audio send queue/thread\n");
// 不影响服务启动,继续执行
}
-
-#if USE_DUAL_STREAM_INTERFACE
- // 使用 old_Start_AIVoice 接口时,在服务初始化时就启动音频
- printf("[LN_MQTT_API] Initializing audio with old_Start_AIVoice dual stream interface\n");
-
- // 检查 AI 语音服务是否已经在运行(如果已运行则先停止)
- if (AI_IsVoiceServiceRunning()) {
- printf("[LN_MQTT_API] AI voice service already running, stopping it first\n");
- StopAIVoice();
- }
-
- // 设置第二个上行流参数:SBC 格式,16kHz,单声道
- AIVoiceAudioParams secondStreamParams = {
- .audioFormat = SBC, // SBC 格式(对应 AudioCodecFormat)
- .channelCount = 1, // 单声道
- .sampleRate = 16000 // 16kHz 采样率
- };
-
- // 输入流参数(主输入流)
- AIVoiceAudioParams inputParams = {
- .audioFormat = SBC,
- .channelCount = 1,
- .sampleRate = 16000
- };
+ // 音频辅助初始化(双流模式下启动 old_Start_AIVoice)
+ // ln_mqtt_audio_init();
-
- // 输出流参数(设置为NULL,因为我们只关心录音输入)
- AIVoiceAudioParams outputParams = {
- .audioFormat = PCM,
- .channelCount = 1,
- .sampleRate = 16000
- };
-
- // 使用 old_Start_AIVoice 启动,传入第二个上行流参数启用双流
- int32_t start_ret = old_Start_AIVoice(
- (AIVoiceDataCallback)ln_mqtt_record_data_cb, // 数据回调函数(类型转换)
- NULL, // 用户数据
- &inputParams, // 输入流参数(主输入流)
- &outputParams, // 输出流参数(NULL使用默认)
- NULL, // 第二个上行流参数(启用双流)
- false // 不使用OGG封装
- );
-
- if (start_ret != 0) {
- printf("[LN_MQTT_API] WARNING: old_Start_AIVoice failed during service init: %d\n", (int)start_ret);
- // 不影响服务启动,继续执行
- } else {
- printf("[LN_MQTT_API] old_Start_AIVoice initialized successfully (SBC, 16kHz, mono)\n");
- }
-#endif /* USE_DUAL_STREAM_INTERFACE */
-
g_ln_mqtt_service_started = true;
printf("[LN_MQTT_API] MQTT service started successfully\n");
// 如果有剩余数据,先刷新
if (g_record_cache.current_size > 0) {
printf("[LN_MQTT_API] Flushing remaining cached audio data before service stop\n");
- if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size) != 0) {
+ if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size, AUDIO_SEND_ENCODING_OPUS) != 0) {
printf("[LN_MQTT_API] Failed to enqueue remaining cached audio data\n");
}
}
g_record_cache.packet_count = 0;
printf("[LN_MQTT_API] Cache buffer freed\n");
}
-
-#if USE_DUAL_STREAM_INTERFACE
- // 清理双流接口资源
- // 清除录音上传标志位
- g_recording_upload_started = false;
- // 停止 AI 语音服务(在服务初始化时已启动)
- if (AI_IsVoiceServiceRunning()) {
- (void)StopAIVoice();
- printf("[LN_MQTT_API] AI voice service stopped\n");
+
+ // 音频辅助反初始化(双流模式下停止 AI 语音服务)
+ ln_mqtt_audio_deinit();
+
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_DISCONNECTED);
}
-#endif /* USE_DUAL_STREAM_INTERFACE */
-
+ g_mqtt_message_callback = NULL;
+
// 停止MQTT主线程(会自动断开连接和清理资源)
uapi_mqtt_main_stop();
cJSON_Delete(root);
return -1;
}
- cJSON_AddStringToObject(audio_params, "format", "sbc");
+ if(g_audio_format_input == PCM )
+ {
+ cJSON_AddStringToObject(audio_params, "format", "pcm");
+ }
+ else if(g_audio_format_input == SBC)
+ {
+ cJSON_AddStringToObject(audio_params, "format", "sbc");
+ }
+
cJSON_AddNumberToObject(audio_params, "sample_rate", 16000);
cJSON_AddNumberToObject(audio_params, "channels", 1);
cJSON_AddNumberToObject(audio_params, "frame_duration", 60);
return -1;
}
+ if(start==false && g_recording_upload_started==false)
+ {
+ start=true;
+ }
+
// 构建JSON数据
cJSON *root = cJSON_CreateObject();
if (!root) {
// 设置录音上传标志位,开始处理并上传音频数据
g_recording_upload_started = true;
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_AUDIO_RECORDING_START);
+ }
printf("[LN_MQTT_API] Dual stream recording started, upload enabled\n");
#else
// 使用原有 MQTT_StartRecord 接口
if (rec_ret != 0) {
printf("[LN_MQTT_API] WARNING: MQTT_StartRecord failed: %d\n", (int)rec_ret);
} else {
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_AUDIO_RECORDING_START);
+ }
printf("[LN_MQTT_API] MQTT_StartRecord started with SBC format (16kHz, mono)\n");
}
#endif /* USE_DUAL_STREAM_INTERFACE */
if (g_record_cache.buffer != NULL && g_record_cache.current_size > 0) {
printf("[LN_MQTT_API] Flushing remaining cached audio data: %u bytes, %u packets\n",
g_record_cache.current_size, g_record_cache.packet_count);
- if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size) != 0) {
+ if (ln_udp_audio_send_enqueue(g_record_cache.buffer, g_record_cache.current_size, AUDIO_SEND_ENCODING_OPUS) != 0) {
printf("[LN_MQTT_API] Failed to enqueue remaining cached audio data\n");
}
g_record_cache.current_size = 0;
g_record_cache.buffer_size = 0;
printf("[LN_MQTT_API] Cache buffer freed\n");
}
-
+
+#if LN_MQTT_RECORD_SAVE_TO_FILE_TEST
+ ln_mqtt_record_test_file_close();
+#endif /* LN_MQTT_RECORD_SAVE_TO_FILE_TEST */
+
#if USE_DUAL_STREAM_INTERFACE
// 清除录音上传标志位,停止处理并上传音频数据
g_recording_upload_started = false;
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_AUDIO_RECORDING_END);
+ }
printf("[LN_MQTT_API] Dual stream recording stopped, upload disabled (AI voice service still running)\n");
#else
+ if (g_mqtt_message_callback != NULL) {
+ g_mqtt_message_callback(NULL, WS_CMD_AUDIO_RECORDING_END);
+ }
// 停止原有 MQTT_StartRecord 接口
(void)MQTT_StopRecord();
#endif /* USE_DUAL_STREAM_INTERFACE */
#include <stdint.h>
#include <stdbool.h>
#include "uapi_Mqtt_api.h"
+#include "ln_api.h"
#ifdef __cplusplus
extern "C" {
/**
* @brief 启动MQTT服务(启动线程、自动连接等)
+ * @param callback 消息处理回调函数,参考 ln_ws_start,可为 NULL 使用默认处理
* @note 启动服务时会自动进行初始化,无需单独调用初始化函数
* @note 服务模式下使用内部回调,自动处理连接状态和消息接收
* @return 0 成功,-1 失败
*/
-int ln_mqtt_api_start_service(void);
+int ln_mqtt_api_start_service(ws_message_callback_t_ln callback);
/**
* @brief 停止MQTT服务(停止线程、断开连接等)
*/
void ln_udp_audio_send_deinit(void);
+/* 音频发送编码类型:与 ln_UDP.c 中 AUDIO_SEND_ENCODING_* 一致 */
+#define AUDIO_SEND_ENCODING_OPUS 0 /* 已是 Opus,直接发送 */
+#define AUDIO_SEND_ENCODING_PCM 1 /* PCM,发送前编码为 Opus */
+
/**
* @brief 将音频数据放入发送队列(供录音回调函数调用)
* @param data 音频数据指针
- * @param size 音频数据大小
+ * @param size 音频数据大小(字节)
+ * @param encoding AUDIO_SEND_ENCODING_OPUS(0)=已是 Opus;AUDIO_SEND_ENCODING_PCM(1)=PCM,发送前编码为 Opus
* @return 0 成功,-1 失败
*/
-int ln_udp_audio_send_enqueue(const uint8_t *data, uint32_t size);
+int ln_udp_audio_send_enqueue(const uint8_t *data, uint32_t size, uint8_t encoding);
#ifdef __cplusplus
(void)strCommonCmd;\r
\r
printf("[LN_MQTT_AT] Starting MQTT service...\n");\r
- int ret = ln_mqtt_api_start_service();\r
+ int ret = ln_mqtt_api_start_service(NULL);\r
if (ret == 0) {\r
printf("+LN_MQTT_START_SERVICE: OK\n");\r
return ERRCODE_SUCC;\r
#include "ln_api.h"
+#ifdef SUPPORT_LN_MQTT_SERVICE
+#include "ln_mqtt_api.h"
+#endif
/* for https/http client */
#include "netstack/http/include/httpclient.h"
/* for HMAC-SHA256 */
// 雷鸟http服务初始化
errcode_t uapi_ln_http_server_init(void)
{
+ #ifdef SUPPORT_LN_MQTT_SERVICE
+ ln_mqtt_api_start_service(ln_ws_process_message);
+ return ERRCODE_SUCC;
+ #endif
printf("uapi_ln_http_server_init !\r\n");
ln_send_taskcfg.create_queue_handle = create_ln_http_send_queue;
// 开始新的音频聊天
int ln_ws_start_audio_chat(ln_audio_chat_command_t command_type)
{
+ #ifdef SUPPORT_LN_MQTT_SERVICE
+
+ ln_mqtt_api_send_listen_state(true);
+
+ return 0;
+
+
+ #else
+
// 检查音频是否已初始化
if (!g_audio_initialized) {
LN_WS_ERROR("Audio not initialized, please call ln_ws_audio_init() first\n");
LN_WS_DEBUG("Audio chat started: %s (command: %s)\n",
g_audio_chat_ctx.chat_id, command_name);
+ #endif
return 0;
}
// 结束当前音频聊天
int ln_ws_end_audio_chat(void)
{
+
+ #ifdef SUPPORT_LN_MQTT_SERVICE
+ ln_mqtt_api_send_listen_state(false);
+ return 0;
+ #else
// 检查音频是否已初始化
if (!g_audio_initialized) {
LN_WS_ERROR("Audio not initialized, please call ln_ws_audio_init() first\n");
g_audio_chat_ending = true;
return 0;
+ #endif
}
// 获取当前聊天ID
void ln_ws_audio_init(bool is_vad_server_enabled)
{
+
+ #ifdef SUPPORT_LN_MQTT_SERVICE
+ ln_mqtt_audio_init();
+ #else
+
// is_vad_server_enabled=false;
// 检查是否已经初始化
if (g_audio_initialized) {
}
}
#endif
+
+#endif
}
/* 获取当前连接状态 */
int ln_ws_get_connection_state(void)
{
+ #ifdef SUPPORT_LN_MQTT_SERVICE
+ // return ln_mqtt_api_get_connection_state();
+ return WS_STATE_CONNECTED;
+ #else
return g_ws_connected;
+ #endif
}
/* 获取连接状态字符串 */
# 应用主程序
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/opus_frame_to_pcm.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/opus_pcm_to_frame.c
)
# 将 opus 库的 .c 源文件全部链接进来(替代原有静态库)
file(GLOB OPUS_CELT "${CMAKE_CURRENT_SOURCE_DIR}/celt/*.c")
file(GLOB OPUS_SILK "${CMAKE_CURRENT_SOURCE_DIR}/silk/*.c")
file(GLOB OPUS_SILK_FLOAT "${CMAKE_CURRENT_SOURCE_DIR}/silk/float/*.c")
+file(GLOB OPUS_SILK_FIXED "${CMAKE_CURRENT_SOURCE_DIR}/silk/fixed/*.c")
# 仅 x86 平台编译 SIMD 优化源;非 x86(如 ARM/Cortex/RISC-V)不包含,使用 C 通用实现
if(CMAKE_SYSTEM_PROCESSOR MATCHES "[xX]86|i686|AMD64|x86_64")
file(GLOB OPUS_CELT_X86 "${CMAKE_CURRENT_SOURCE_DIR}/celt/x86/*.c")
file(GLOB OPUS_SILK_X86 "${CMAKE_CURRENT_SOURCE_DIR}/silk/x86/*.c")
- list(APPEND SOURCES ${OPUS_SRC_LIB} ${OPUS_CELT} ${OPUS_CELT_X86} ${OPUS_SILK} ${OPUS_SILK_FLOAT} ${OPUS_SILK_X86})
+ # x86 使用 fixed 的 C/SSE4.1 实现,排除 ARM NEON 文件
+ list(REMOVE_ITEM OPUS_SILK_FIXED "${CMAKE_CURRENT_SOURCE_DIR}/silk/fixed/warped_autocorrelation_FIX_neon_intr.c")
+ list(APPEND SOURCES ${OPUS_SRC_LIB} ${OPUS_CELT} ${OPUS_CELT_X86} ${OPUS_SILK} ${OPUS_SILK_FLOAT} ${OPUS_SILK_FIXED} ${OPUS_SILK_X86})
else()
- # 非 x86 平台:排除 x86 特定的 AVX2 文件
+ # 非 x86 平台:排除 float 的 AVX2、fixed 的 SSE4.1/NEON 架构特定文件
list(REMOVE_ITEM OPUS_SILK_FLOAT "${CMAKE_CURRENT_SOURCE_DIR}/silk/float/inner_product_FLP_avx2.c")
- list(APPEND SOURCES ${OPUS_SRC_LIB} ${OPUS_CELT} ${OPUS_SILK} ${OPUS_SILK_FLOAT})
+ list(REMOVE_ITEM OPUS_SILK_FIXED "${CMAKE_CURRENT_SOURCE_DIR}/silk/fixed/vector_ops_FIX_sse4_1.c")
+ list(REMOVE_ITEM OPUS_SILK_FIXED "${CMAKE_CURRENT_SOURCE_DIR}/silk/fixed/burg_modified_FIX_sse4_1.c")
+ list(REMOVE_ITEM OPUS_SILK_FIXED "${CMAKE_CURRENT_SOURCE_DIR}/silk/fixed/warped_autocorrelation_FIX_neon_intr.c")
+ list(APPEND SOURCES ${OPUS_SRC_LIB} ${OPUS_CELT} ${OPUS_SILK} ${OPUS_SILK_FLOAT} ${OPUS_SILK_FIXED})
endif()
# 头文件目录
${CMAKE_CURRENT_SOURCE_DIR}/src_lib
${CMAKE_CURRENT_SOURCE_DIR}/silk
${CMAKE_CURRENT_SOURCE_DIR}/silk/float
+ ${CMAKE_CURRENT_SOURCE_DIR}/silk/fixed
${CMAKE_CURRENT_SOURCE_DIR}/celt
)
--- /dev/null
+# Opus 编码器支持说明\r
+\r
+本文档说明如何在 `test_opus_frame_to_pcm` 目录中添加编码器支持。\r
+\r
+## 概述\r
+\r
+默认情况下,`test_opus_frame_to_pcm` 目录只包含解码器相关的源码,用于构建最小化的解码库。如果需要编码功能,需要额外复制编码器相关的源文件。\r
+\r
+## 快速开始\r
+\r
+### 1. 复制解码器源码(如果还没有)\r
+\r
+首先确保已经复制了解码器源码:\r
+\r
+**Linux/macOS:**\r
+```bash\r
+cd test_opus_frame_to_pcm\r
+./copy_sources.sh\r
+```\r
+\r
+**Windows PowerShell:**\r
+```powershell\r
+cd test_opus_frame_to_pcm\r
+.\copy_sources.ps1 # 如果有的话,或者使用 Git Bash 运行 copy_sources.sh\r
+```\r
+\r
+### 2. 复制编码器源码\r
+\r
+运行编码器源码复制脚本:\r
+\r
+**Linux/macOS:**\r
+```bash\r
+./copy_encoder_sources.sh\r
+```\r
+\r
+**Windows PowerShell:**\r
+```powershell\r
+.\copy_encoder_sources.ps1\r
+```\r
+\r
+### 3. 编译库\r
+\r
+使用更新后的 Makefile 编译包含编码器的库:\r
+\r
+```bash\r
+make -f Makefile.libopus clean\r
+make -f Makefile.libopus\r
+```\r
+\r
+这将生成包含编码器和解码器功能的 `libopus_min.a`。\r
+\r
+### 4. 测试编码功能\r
+\r
+编译编码工具并测试:\r
+\r
+```bash\r
+make clean\r
+make\r
+```\r
+\r
+然后测试编码功能:\r
+\r
+```bash\r
+# 编码:PCM -> Opus\r
+./opus_frame_to_pcm -e input.pcm -o output.opus -r 16000 -c 1 -b 64000 -a 1\r
+\r
+# 或使用独立的编码工具\r
+./opus_pcm_to_frame input.pcm -o output.opus -r 16000 -c 1 -b 64000 -a 1\r
+```\r
+\r
+## 添加的编码器源文件\r
+\r
+### Opus API 层(6 个文件)\r
+- `src/opus_encoder.c` - Opus 编码器主实现\r
+- `src/opus_multistream_encoder.c` - 多流编码器\r
+- `src/opus_projection_encoder.c` - 投影编码器\r
+- `src/analysis.c` - 编码分析(VAD 和带宽检测)\r
+- `src/mlp.c` - MLP 神经网络\r
+- `src/mlp_data.c` - MLP 数据\r
+\r
+### CELT 编码器(1 个文件)\r
+- `celt/celt_encoder.c` - CELT 编码器核心\r
+\r
+### SILK 编码器(约 30 个文件)\r
+- **核心编码文件(8 个)**\r
+ - `silk/enc_API.c`\r
+ - `silk/init_encoder.c`\r
+ - `silk/encode_indices.c`\r
+ - `silk/encode_pulses.c`\r
+ - `silk/NLSF_encode.c`\r
+ - `silk/NLSF_VQ.c`\r
+ - `silk/NLSF_del_dec_quant.c`\r
+ - `silk/process_NLSFs.c`\r
+\r
+- **立体声编码(3 个)**\r
+ - `silk/stereo_LR_to_MS.c`\r
+ - `silk/stereo_encode_pred.c`\r
+ - `silk/stereo_quant_pred.c`\r
+\r
+- **NSQ(噪声整形量化)(2 个)**\r
+ - `silk/NSQ.c`\r
+ - `silk/NSQ_del_dec.c`\r
+\r
+- **控制和分析(8 个)**\r
+ - `silk/quant_LTP_gains.c`\r
+ - `silk/VQ_WMat_EC.c`\r
+ - `silk/VAD.c`\r
+ - `silk/control_audio_bandwidth.c`\r
+ - `silk/control_SNR.c`\r
+ - `silk/control_codec.c`\r
+ - `silk/check_control_input.c`\r
+ - `silk/ana_filt_bank_1.c`\r
+\r
+- **浮点实现(1 个)**\r
+ - `silk/float/encode_frame_FLP.c`\r
+\r
+- **定点实现(约 20 个)**\r
+ - `silk/fixed/*.c` 中的所有编码相关文件\r
+\r
+## 库大小对比\r
+\r
+- **仅解码器**: 约 500-600 KB\r
+- **编码器+解码器**: 约 800-1000 KB\r
+\r
+编码器会增加约 300-400 KB 的库大小。\r
+\r
+## 注意事项\r
+\r
+1. **必须先复制解码器源码**:编码器脚本假设解码器源码已经存在。\r
+\r
+2. **Makefile 已更新**:`Makefile.libopus` 已经更新以支持编码器源文件。如果只想要解码器,可以注释掉编码器相关的源文件定义。\r
+\r
+3. **编译时间**:包含编码器后,编译时间会显著增加(约 2-3 倍)。\r
+\r
+4. **依赖关系**:编码器需要 `entenc.c`(熵编码器),这个文件在解码器构建中已经包含。\r
+\r
+## 故障排除\r
+\r
+### 编译错误:找不到编码器源文件\r
+\r
+确保已经运行了 `copy_encoder_sources.sh` 或 `copy_encoder_sources.ps1`。\r
+\r
+### 链接错误:未定义的编码器函数\r
+\r
+检查 `Makefile.libopus` 中是否包含了所有编码器源文件。\r
+\r
+### 运行时错误:编码失败\r
+\r
+检查输入 PCM 文件的格式:\r
+- 必须是 16 位 PCM\r
+- 小端序(little-endian)\r
+- 正确的采样率和声道数\r
+\r
+## 相关文件\r
+\r
+- `copy_encoder_sources.sh` - Linux/macOS 编码器源码复制脚本\r
+- `copy_encoder_sources.ps1` - Windows PowerShell 编码器源码复制脚本\r
+- `Makefile.libopus` - 库构建 Makefile(已更新支持编码器)\r
+- `src/opus_pcm_to_frame.c` - 独立的编码工具\r
+- `src/opus_frame_to_pcm.c` - 统一的编解码工具(支持 `-e` 选项)\r
SRC_DIR = src\r
INCLUDE_DIR = include\r
\r
-# Target executable\r
+# Target executables\r
TARGET = opus_frame_to_pcm\r
+TARGET_ENCODE = opus_pcm_to_frame\r
\r
-# Source file\r
+# Source files\r
SOURCES = $(SRC_DIR)/opus_frame_to_pcm.c\r
+SOURCES_ENCODE = $(SRC_DIR)/opus_pcm_to_frame.c\r
\r
# Object files\r
OBJECTS = $(SOURCES:.c=.o)\r
+OBJECTS_ENCODE = $(SOURCES_ENCODE:.c=.o)\r
\r
# Default target\r
-all: $(TARGET)\r
+all: $(TARGET) $(TARGET_ENCODE)\r
\r
# Build executable\r
LIBOPUS ?= libopus_min.a\r
# Ensure we link against the chosen archive name\r
@if [ "$(LIBOPUS)" != "libopus.a" ]; then \\r
rm -f libopus.a; \\r
- ln -s "$(LIBOPUS)" libopus.a; \\r
+ if command -v ln >/dev/null 2>&1; then \\r
+ ln -s "$(LIBOPUS)" libopus.a; \\r
+ else \\r
+ cp "$(LIBOPUS)" libopus.a; \\r
+ fi; \\r
fi\r
$(CC) $(OBJECTS) -o $(TARGET) $(LDFLAGS)\r
\r
+$(TARGET_ENCODE): $(OBJECTS_ENCODE) $(LIBOPUS)\r
+ # Ensure we link against the chosen archive name\r
+ @if [ "$(LIBOPUS)" != "libopus.a" ]; then \\r
+ rm -f libopus.a; \\r
+ if command -v ln >/dev/null 2>&1; then \\r
+ ln -s "$(LIBOPUS)" libopus.a; \\r
+ else \\r
+ cp "$(LIBOPUS)" libopus.a; \\r
+ fi; \\r
+ fi\r
+ $(CC) $(OBJECTS_ENCODE) -o $(TARGET_ENCODE) $(LDFLAGS)\r
+\r
# Compile source files\r
$(SRC_DIR)/%.o: $(SRC_DIR)/%.c\r
$(CC) $(CFLAGS) -c $< -o $@\r
\r
-# Check if libopus.a exists\r
+# Check if libopus.a exists and build it if needed\r
$(LIBOPUS):\r
@if [ ! -f $(LIBOPUS) ]; then \\r
- echo "Error: libopus.a not found!"; \\r
- echo "Please create $(LIBOPUS) first."; \\r
- echo "Recommended (PowerShell):"; \\r
- echo " ./build_min_libopus.ps1"; \\r
- echo "Fallback: copy the full libopus.a as $(LIBOPUS) (NOT recommended for size validation)."; \\r
- exit 1; \\r
+ echo "Error: $(LIBOPUS) not found!"; \\r
+ echo "Building $(LIBOPUS) using Makefile.libopus..."; \\r
+ $(MAKE) -f Makefile.libopus $(LIBOPUS) || ( \\r
+ echo "Build failed. Please ensure:"; \\r
+ echo " 1. Source files are copied (run copy_sources.sh)"; \\r
+ echo " 2. Encoder sources are copied if needed (run copy_encoder_sources.sh)"; \\r
+ echo " 3. config.h exists in this directory"; \\r
+ exit 1 \\r
+ ); \\r
fi\r
\r
# Clean build artifacts\r
clean:\r
- rm -f $(OBJECTS) $(TARGET)\r
+ rm -f $(OBJECTS) $(OBJECTS_ENCODE) $(TARGET) $(TARGET_ENCODE)\r
\r
# Test with a sample file (if available)\r
test: $(TARGET)\r
echo "No test_frame.opus found. Please provide a test file."; \\r
fi\r
\r
-.PHONY: all clean test\r
+.PHONY: all clean test encode-only decode-only\r
+\r
+# Build only decode tool\r
+decode-only: $(TARGET)\r
+\r
+# Build only encode tool\r
+encode-only: $(TARGET_ENCODE)\r
-# Makefile for building minimal Opus decoder library (libopus_min.a)\r
-# This builds a decoder-only library from source files\r
+# Makefile for building minimal Opus library (libopus_min.a)\r
+# This builds a library with both encoder and decoder support\r
\r
CC = gcc\r
AR = ar\r
CELT_DIR = celt\r
SILK_DIR = silk\r
\r
-# Opus API layer sources (decoder only)\r
+# Opus API layer sources (decoder only, encoder added if available)\r
OPUS_SOURCES = \\r
$(SRC_LIB_DIR)/opus.c \\r
$(SRC_LIB_DIR)/opus_decoder.c \\r
$(SRC_LIB_DIR)/repacketizer.c \\r
$(SRC_LIB_DIR)/mapping_matrix.c\r
\r
-# CELT decoder sources\r
+# Add encoder sources if they exist\r
+ifeq ($(wildcard $(SRC_LIB_DIR)/opus_encoder.c),$(SRC_LIB_DIR)/opus_encoder.c)\r
+OPUS_SOURCES += \\r
+ $(SRC_LIB_DIR)/opus_encoder.c \\r
+ $(SRC_LIB_DIR)/opus_multistream_encoder.c \\r
+ $(SRC_LIB_DIR)/opus_projection_encoder.c \\r
+ $(SRC_LIB_DIR)/analysis.c \\r
+ $(SRC_LIB_DIR)/mlp.c \\r
+ $(SRC_LIB_DIR)/mlp_data.c\r
+ENCODER_SUPPORT = 1\r
+else\r
+ENCODER_SUPPORT = 0\r
+endif\r
+\r
+# CELT decoder sources (encoder added if available)\r
CELT_SOURCES = \\r
$(CELT_DIR)/bands.c \\r
$(CELT_DIR)/celt.c \\r
$(CELT_DIR)/rate.c \\r
$(CELT_DIR)/vq.c\r
\r
+# Add CELT encoder if available\r
+ifeq ($(wildcard $(CELT_DIR)/celt_encoder.c),$(CELT_DIR)/celt_encoder.c)\r
+CELT_SOURCES += $(CELT_DIR)/celt_encoder.c\r
+endif\r
+\r
# CELT x86 optimization (if available)\r
CELT_X86_SOURCES = \\r
$(CELT_DIR)/x86/x86cpu.c \\r
$(SILK_DIR)/decode_pulses.c \\r
$(SILK_DIR)/decoder_set_fs.c\r
\r
+# SILK encoder sources (core) - only if available\r
+SILK_ENCODER_CORE_SOURCES = \r
+ifeq ($(wildcard $(SILK_DIR)/enc_API.c),$(SILK_DIR)/enc_API.c)\r
+SILK_ENCODER_CORE_SOURCES += \\r
+ $(SILK_DIR)/enc_API.c \\r
+ $(SILK_DIR)/init_encoder.c \\r
+ $(SILK_DIR)/encode_indices.c \\r
+ $(SILK_DIR)/encode_pulses.c \\r
+ $(SILK_DIR)/NLSF_encode.c \\r
+ $(SILK_DIR)/NLSF_VQ.c \\r
+ $(SILK_DIR)/NLSF_del_dec_quant.c \\r
+ $(SILK_DIR)/process_NLSFs.c\r
+endif\r
+\r
# SILK signal processing (shared)\r
SILK_SIGNAL_SOURCES = \\r
$(SILK_DIR)/CNG.c \\r
$(SILK_DIR)/table_LSF_cos.c \\r
$(SILK_DIR)/LPC_inv_pred_gain.c\r
\r
-# SILK stereo processing\r
+# SILK stereo processing (decoder, encoder added if available)\r
SILK_STEREO_SOURCES = \\r
$(SILK_DIR)/stereo_MS_to_LR.c \\r
$(SILK_DIR)/stereo_decode_pred.c \\r
$(SILK_DIR)/stereo_find_predictor.c\r
\r
+# Add encoder stereo processing if available\r
+ifeq ($(wildcard $(SILK_DIR)/stereo_LR_to_MS.c),$(SILK_DIR)/stereo_LR_to_MS.c)\r
+SILK_STEREO_SOURCES += \\r
+ $(SILK_DIR)/stereo_LR_to_MS.c \\r
+ $(SILK_DIR)/stereo_encode_pred.c \\r
+ $(SILK_DIR)/stereo_quant_pred.c\r
+endif\r
+\r
# SILK tables\r
SILK_TABLE_SOURCES = \\r
$(SILK_DIR)/tables_gain.c \\r
$(SILK_DIR)/sum_sqr_shift.c \\r
$(SILK_DIR)/gain_quant.c\r
\r
+# SILK encoder NSQ (Noise Shaping Quantization) - only if available\r
+SILK_ENCODER_NSQ_SOURCES = \r
+ifeq ($(wildcard $(SILK_DIR)/NSQ.c),$(SILK_DIR)/NSQ.c)\r
+SILK_ENCODER_NSQ_SOURCES += \\r
+ $(SILK_DIR)/NSQ.c \\r
+ $(SILK_DIR)/NSQ_del_dec.c\r
+endif\r
+\r
+# SILK encoder control and analysis - only if available\r
+SILK_ENCODER_CONTROL_SOURCES = \r
+ifeq ($(wildcard $(SILK_DIR)/VAD.c),$(SILK_DIR)/VAD.c)\r
+SILK_ENCODER_CONTROL_SOURCES += \\r
+ $(SILK_DIR)/quant_LTP_gains.c \\r
+ $(SILK_DIR)/VQ_WMat_EC.c \\r
+ $(SILK_DIR)/VAD.c \\r
+ $(SILK_DIR)/control_audio_bandwidth.c \\r
+ $(SILK_DIR)/control_SNR.c \\r
+ $(SILK_DIR)/control_codec.c \\r
+ $(SILK_DIR)/check_control_input.c \\r
+ $(SILK_DIR)/ana_filt_bank_1.c\r
+endif\r
+\r
# SILK float implementation (default, comment out if using fixed-point)\r
SILK_FLOAT_SOURCES = \\r
$(SILK_DIR)/float/apply_sine_window_FLP.c \\r
$(SILK_DIR)/float/schur_FLP.c \\r
$(SILK_DIR)/float/sort_FLP.c\r
\r
+# Add encode_frame_FLP.c if available\r
+ifeq ($(wildcard $(SILK_DIR)/float/encode_frame_FLP.c),$(SILK_DIR)/float/encode_frame_FLP.c)\r
+SILK_FLOAT_SOURCES += $(SILK_DIR)/float/encode_frame_FLP.c\r
+endif\r
+\r
+# SILK fixed-point implementation (encoder) - only if available\r
+SILK_FIXED_SOURCES = \r
+ifeq ($(wildcard $(SILK_DIR)/fixed/encode_frame_FIX.c),$(SILK_DIR)/fixed/encode_frame_FIX.c)\r
+SILK_FIXED_SOURCES += \\r
+ $(SILK_DIR)/fixed/apply_sine_window_FIX.c \\r
+ $(SILK_DIR)/fixed/autocorr_FIX.c \\r
+ $(SILK_DIR)/fixed/burg_modified_FIX.c \\r
+ $(SILK_DIR)/fixed/corrMatrix_FIX.c \\r
+ $(SILK_DIR)/fixed/encode_frame_FIX.c \\r
+ $(SILK_DIR)/fixed/find_LPC_FIX.c \\r
+ $(SILK_DIR)/fixed/find_LTP_FIX.c \\r
+ $(SILK_DIR)/fixed/find_pitch_lags_FIX.c \\r
+ $(SILK_DIR)/fixed/find_pred_coefs_FIX.c \\r
+ $(SILK_DIR)/fixed/k2a_FIX.c \\r
+ $(SILK_DIR)/fixed/k2a_Q16_FIX.c \\r
+ $(SILK_DIR)/fixed/LTP_analysis_filter_FIX.c \\r
+ $(SILK_DIR)/fixed/LTP_scale_ctrl_FIX.c \\r
+ $(SILK_DIR)/fixed/noise_shape_analysis_FIX.c \\r
+ $(SILK_DIR)/fixed/pitch_analysis_core_FIX.c \\r
+ $(SILK_DIR)/fixed/process_gains_FIX.c \\r
+ $(SILK_DIR)/fixed/regularize_correlations_FIX.c \\r
+ $(SILK_DIR)/fixed/residual_energy_FIX.c \\r
+ $(SILK_DIR)/fixed/residual_energy16_FIX.c \\r
+ $(SILK_DIR)/fixed/schur_FIX.c \\r
+ $(SILK_DIR)/fixed/schur64_FIX.c \\r
+ $(SILK_DIR)/fixed/vector_ops_FIX.c \\r
+ $(SILK_DIR)/fixed/warped_autocorrelation_FIX.c\r
+endif\r
+\r
# SILK x86 optimization (if available)\r
SILK_X86_SOURCES = \\r
$(SILK_DIR)/x86/x86_silk_map.c\r
$(CELT_SOURCES) \\r
$(CELT_X86_SOURCES) \\r
$(SILK_CORE_SOURCES) \\r
+ $(SILK_ENCODER_CORE_SOURCES) \\r
$(SILK_SIGNAL_SOURCES) \\r
$(SILK_NLSF_SOURCES) \\r
$(SILK_STEREO_SOURCES) \\r
$(SILK_TABLE_SOURCES) \\r
$(SILK_HELPER_SOURCES) \\r
+ $(SILK_ENCODER_NSQ_SOURCES) \\r
+ $(SILK_ENCODER_CONTROL_SOURCES) \\r
$(SILK_FLOAT_SOURCES) \\r
+ $(SILK_FIXED_SOURCES) \\r
$(SILK_X86_SOURCES)\r
\r
# Object files\r
# Build library\r
$(LIBRARY): $(OBJECTS)\r
@echo "Creating $(LIBRARY)..."\r
+ @if [ "$(ENCODER_SUPPORT)" = "1" ]; then \\r
+ echo "Building with encoder support"; \\r
+ else \\r
+ echo "Building decoder-only library"; \\r
+ fi\r
$(AR) rcs $(LIBRARY) $(OBJECTS)\r
$(RANLIB) $(LIBRARY)\r
@echo "Library created: $(LIBRARY)"\r
--- /dev/null
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CELT_ENCODER_C
+
+#include "cpu_support.h"
+#include "os_support.h"
+#include "mdct.h"
+#include <math.h>
+#include "celt.h"
+#include "pitch.h"
+#include "bands.h"
+#include "modes.h"
+#include "entcode.h"
+#include "quant_bands.h"
+#include "rate.h"
+#include "stack_alloc.h"
+#include "mathops.h"
+#include "float_cast.h"
+#include <stdarg.h>
+#include "celt_lpc.h"
+#include "vq.h"
+
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+
+/** Encoder state
+ @brief Encoder state
+ */
+struct OpusCustomEncoder {
+ const OpusCustomMode *mode; /**< Mode used by the encoder */
+ int channels;
+ int stream_channels;
+
+ int force_intra;
+ int clip;
+ int disable_pf;
+ int complexity;
+ int upsample;
+ int start, end;
+
+ opus_int32 bitrate;
+ int vbr;
+ int signalling;
+ int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */
+ int loss_rate;
+ int lsb_depth;
+ int lfe;
+ int disable_inv;
+ int arch;
+#ifdef ENABLE_QEXT
+ int enable_qext;
+ int qext_scale;
+#endif
+
+ /* Everything beyond this point gets cleared on a reset */
+#define ENCODER_RESET_START rng
+
+ opus_uint32 rng;
+ int spread_decision;
+ opus_val32 delayedIntra;
+ int tonal_average;
+ int lastCodedBands;
+ int hf_average;
+ int tapset_decision;
+
+ int prefilter_period;
+ opus_val16 prefilter_gain;
+ int prefilter_tapset;
+#ifdef RESYNTH
+ int prefilter_period_old;
+ opus_val16 prefilter_gain_old;
+ int prefilter_tapset_old;
+#endif
+ int consec_transient;
+ AnalysisInfo analysis;
+ SILKInfo silk_info;
+
+ opus_val32 preemph_memE[2];
+ opus_val32 preemph_memD[2];
+
+ /* VBR-related parameters */
+ opus_int32 vbr_reservoir;
+ opus_int32 vbr_drift;
+ opus_int32 vbr_offset;
+ opus_int32 vbr_count;
+ opus_val32 overlap_max;
+ opus_val16 stereo_saving;
+ int intensity;
+ celt_glog *energy_mask;
+ celt_glog spec_avg;
+
+#ifdef RESYNTH
+#ifdef ENABLE_QEXT
+ /* +MAX_PERIOD/2 to make space for overlap */
+ celt_sig syn_mem[2][2*DEC_PITCH_BUF_SIZE+MAX_PERIOD];
+#else
+ /* +MAX_PERIOD/2 to make space for overlap */
+ celt_sig syn_mem[2][DEC_PITCH_BUF_SIZE+MAX_PERIOD/2];
+#endif
+#endif
+
+ celt_sig in_mem[1]; /* Size = channels*mode->overlap */
+ /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */
+ /* celt_glog oldBandE[], Size = channels*mode->nbEBands */
+ /* celt_glog oldLogE[], Size = channels*mode->nbEBands */
+ /* celt_glog oldLogE2[], Size = channels*mode->nbEBands */
+ /* celt_glog energyError[], Size = channels*mode->nbEBands */
+};
+
+int celt_encoder_get_size(int channels)
+{
+#ifdef ENABLE_QEXT
+ CELTMode *mode = opus_custom_mode_create(96000, 1920, NULL);
+#else
+ CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+#endif
+ return opus_custom_encoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels)
+{
+ int extra=0;
+ int size;
+#ifdef ENABLE_QEXT
+ int qext_scale;
+ extra = channels*NB_QEXT_BANDS*sizeof(celt_glog);
+ if (mode->Fs == 96000 && (mode->shortMdctSize==240 || mode->shortMdctSize==180)) {
+ qext_scale = 2;
+ } else qext_scale = 1;
+#endif
+ size = sizeof(struct CELTEncoder)
+ + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */
+ + channels*QEXT_SCALE(COMBFILTER_MAXPERIOD)*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */
+ + 4*channels*mode->nbEBands*sizeof(celt_glog) /* celt_glog oldBandE[channels*mode->nbEBands]; */
+ /* celt_glog oldLogE[channels*mode->nbEBands]; */
+ /* celt_glog oldLogE2[channels*mode->nbEBands]; */
+ /* celt_glog energyError[channels*mode->nbEBands]; */
+ + extra;
+ return size;
+}
+
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error)
+{
+ int ret;
+ CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels));
+ /* init will handle the NULL case */
+ ret = opus_custom_encoder_init(st, mode, channels);
+ if (ret != OPUS_OK)
+ {
+ opus_custom_encoder_destroy(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+#endif /* CUSTOM_MODES */
+
+static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode,
+ int channels, int arch)
+{
+ if (channels < 0 || channels > 2)
+ return OPUS_BAD_ARG;
+
+ if (st==NULL || mode==NULL)
+ return OPUS_ALLOC_FAIL;
+
+ OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels));
+
+ st->mode = mode;
+ st->stream_channels = st->channels = channels;
+
+ st->upsample = 1;
+ st->start = 0;
+ st->end = st->mode->effEBands;
+ st->signalling = 1;
+ st->arch = arch;
+
+ st->constrained_vbr = 1;
+ st->clip = 1;
+
+ st->bitrate = OPUS_BITRATE_MAX;
+ st->vbr = 0;
+ st->force_intra = 0;
+ st->complexity = 5;
+ st->lsb_depth=24;
+
+#ifdef ENABLE_QEXT
+ if (st->mode->Fs == 96000 && (mode->shortMdctSize==240 || mode->shortMdctSize==180)) st->qext_scale = 2;
+ else st->qext_scale = 1;
+#endif
+
+ opus_custom_encoder_ctl(st, OPUS_RESET_STATE);
+
+ return OPUS_OK;
+}
+
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels)
+{
+ return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch());
+}
+#endif
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+ int arch)
+{
+ int ret;
+#ifdef ENABLE_QEXT
+ if (sampling_rate==96000) {
+ st->upsample = 1;
+ return opus_custom_encoder_init_arch(st,
+ opus_custom_mode_create(96000, 1920, NULL), channels, arch);
+ }
+#endif
+ ret = opus_custom_encoder_init_arch(st,
+ opus_custom_mode_create(48000, 960, NULL), channels, arch);
+ if (ret != OPUS_OK)
+ return ret;
+ st->upsample = resampling_factor(sampling_rate);
+ return OPUS_OK;
+}
+
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+void opus_custom_encoder_destroy(CELTEncoder *st)
+{
+ opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+
+static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C,
+ opus_val16 *tf_estimate, int *tf_chan, int allow_weak_transients,
+ int *weak_transient, opus_val16 tone_freq, opus_val32 toneishness)
+{
+ int i;
+ VARDECL(opus_val16, tmp);
+ opus_val32 mem0,mem1;
+ int is_transient = 0;
+ opus_int32 mask_metric = 0;
+ int c;
+ opus_val16 tf_max;
+ int len2;
+ /* Forward masking: 6.7 dB/ms. */
+#ifdef FIXED_POINT
+ int forward_shift = 4;
+#else
+ opus_val16 forward_decay = QCONST16(.0625f,15);
+#endif
+ /* Table of 6*64/x, trained on real data to minimize the average error */
+ static const unsigned char inv_table[128] = {
+ 255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25,
+ 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
+ 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
+ };
+ SAVE_STACK;
+#ifdef FIXED_POINT
+ int in_shift = IMAX(0, celt_ilog2(1+celt_maxabs32(in, C*len))-14);
+#endif
+ 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++)
+ {
+ opus_val32 mean;
+ opus_int32 unmask=0;
+ opus_val32 norm;
+ opus_val16 maxE;
+ mem0=0;
+ mem1=0;
+ /* High-pass filter: (1 - 2*z^-1 + z^-2) / (1 - z^-1 + .5*z^-2) */
+ for (i=0;i<len;i++)
+ {
+#ifndef FIXED_POINT
+ float mem00;
+#endif
+ opus_val32 x,y;
+ x = SHR32(in[i+c*len],in_shift);
+ y = ADD32(mem0, x);
+#ifdef FIXED_POINT
+ mem0 = mem1 + y - SHL32(x,1);
+ mem1 = x - SHR32(y,1);
+#else
+ /* Original code:
+ mem0 = mem1 + y - 2*x;
+ mem1 = x - .5f*y;
+ Modified code to shorten dependency chains: */
+ mem00=mem0;
+ mem0 = mem0 - x + .5f*mem1;
+ mem1 = x - mem00;
+#endif
+ tmp[i] = SROUND16(y, 2);
+ /*printf("%f ", tmp[i]);*/
+ }
+ /*printf("\n");*/
+ /* First few samples are bad because we don't propagate the memory */
+ OPUS_CLEAR(tmp, 12);
+
+#ifdef FIXED_POINT
+ /* Normalize tmp to max range */
+ {
+ int shift=0;
+ shift = 14-celt_ilog2(MAX16(1, celt_maxabs16(tmp, len)));
+ if (shift!=0)
+ {
+ for (i=0;i<len;i++)
+ tmp[i] = SHL16(tmp[i], shift);
+ }
+ }
+#endif
+
+ mean=0;
+ mem0=0;
+ /* Grouping by two to reduce complexity */
+ /* Forward pass to compute the post-echo threshold*/
+ for (i=0;i<len2;i++)
+ {
+ opus_val32 x2 = PSHR32(MULT16_16(tmp[2*i],tmp[2*i]) + MULT16_16(tmp[2*i+1],tmp[2*i+1]),4);
+ mean += PSHR32(x2, 12);
+#ifdef FIXED_POINT
+ /* FIXME: Use PSHR16() instead */
+ mem0 = mem0 + PSHR32(x2-mem0,forward_shift);
+ tmp[i] = PSHR32(mem0, 12);
+#else
+ mem0 = x2 + (1.f-forward_decay)*mem0;
+ tmp[i] = forward_decay*mem0;
+#endif
+ }
+
+ mem0=0;
+ maxE=0;
+ /* 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 */
+ mem0 = mem0 + PSHR32(SHL32(tmp[i],4)-mem0,3);
+ tmp[i] = PSHR32(mem0, 4);
+ maxE = MAX16(maxE, tmp[i]);
+#else
+ mem0 = tmp[i] + 0.875f*mem0;
+ tmp[i] = 0.125f*mem0;
+ maxE = MAX16(maxE, 0.125f*mem0);
+#endif
+ }
+ /*for (i=0;i<len2;i++)printf("%f ", tmp[i]/mean);printf("\n");*/
+
+ /* Compute the ratio of the "frame energy" over the harmonic mean of the energy.
+ This essentially corresponds to a bitrate-normalized temporal noise-to-mask
+ ratio */
+
+ /* As a compromise with the old transient detector, frame energy is the
+ geometric mean of the energy and half the max */
+#ifdef FIXED_POINT
+ /* Costs two sqrt() to avoid overflows */
+ mean = MULT16_16(celt_sqrt(mean), celt_sqrt(MULT16_16(maxE,len2>>1)));
+#else
+ mean = celt_sqrt(mean * maxE*.5*len2);
+#endif
+ /* Inverse of the mean energy in Q15+6 */
+ norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1));
+ /* Compute harmonic mean discarding the unreliable boundaries
+ The data is smooth, so we only take 1/4th of the samples */
+ unmask=0;
+ /* We should never see NaNs here. If we find any, then something really bad happened and we better abort
+ before it does any damage later on. If these asserts are disabled (no hardening), then the table
+ lookup a few lines below (id = ...) is likely to crash dur to an out-of-bounds read. DO NOT FIX
+ that crash on NaN since it could result in a worse issue later on. */
+ celt_assert(!celt_isnan(tmp[0]));
+ celt_assert(!celt_isnan(norm));
+ for (i=12;i<len2-5;i+=4)
+ {
+ int id;
+#ifdef FIXED_POINT
+ id = MAX32(0,MIN32(127,MULT16_32_Q15(tmp[i]+EPSILON,norm))); /* Do not round to nearest */
+#else
+ id = (int)MAX32(0,MIN32(127,floor(64*norm*(tmp[i]+EPSILON)))); /* Do not round to nearest */
+#endif
+ unmask += inv_table[id];
+ }
+ /*printf("%d\n", unmask);*/
+ /* Normalize, compensate for the 1/4th of the sample and the factor of 6 in the inverse table */
+ unmask = 64*unmask*4/(6*(len2-17));
+ if (unmask>mask_metric)
+ {
+ *tf_chan = c;
+ mask_metric = unmask;
+ }
+ }
+ is_transient = mask_metric>200;
+ /* Prevent the transient detector from confusing the partial cycle of a
+ very low frequency tone with a transient. */
+ if (toneishness > QCONST32(.98f, 29) && tone_freq < QCONST16(0.026f, 13))
+ {
+ is_transient = 0;
+ mask_metric = 0;
+ }
+ /* For low bitrates, define "weak transients" that need to be
+ handled differently to avoid partial collapse. */
+ if (allow_weak_transients && is_transient && mask_metric<600) {
+ is_transient = 0;
+ *weak_transient = 1;
+ }
+ /* Arbitrary metric for VBR boost */
+ tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42);
+ /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */
+ *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28)));
+ /*printf("%d %f\n", tf_max, mask_metric);*/
+ RESTORE_STACK;
+#ifdef FUZZING
+ is_transient = rand()&0x1;
+#endif
+ /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/
+ return is_transient;
+}
+
+/* Looks for sudden increases of energy to decide whether we need to patch
+ the transient decision */
+static int patch_transient_decision(celt_glog *newE, celt_glog *oldE, int nbEBands,
+ int start, int end, int C)
+{
+ int i, c;
+ opus_val32 mean_diff=0;
+ celt_glog spread_old[26];
+ /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to
+ avoid false detection caused by irrelevant bands */
+ if (C==1)
+ {
+ spread_old[start] = oldE[start];
+ for (i=start+1;i<end;i++)
+ spread_old[i] = MAXG(spread_old[i-1]-GCONST(1.0f), oldE[i]);
+ } else {
+ spread_old[start] = MAXG(oldE[start],oldE[start+nbEBands]);
+ for (i=start+1;i<end;i++)
+ spread_old[i] = MAXG(spread_old[i-1]-GCONST(1.0f),
+ MAXG(oldE[i],oldE[i+nbEBands]));
+ }
+ for (i=end-2;i>=start;i--)
+ spread_old[i] = MAXG(spread_old[i], spread_old[i+1]-GCONST(1.0f));
+ /* Compute mean increase */
+ c=0; do {
+ for (i=IMAX(2,start);i<end-1;i++)
+ {
+ opus_val16 x1, x2;
+ x1 = MAXG(0, newE[i + c*nbEBands]);
+ x2 = MAXG(0, spread_old[i]);
+ mean_diff = ADD32(mean_diff, MAXG(0, SUB32(x1, x2)));
+ }
+ } while (++c<C);
+ mean_diff = DIV32(mean_diff, C*(end-1-IMAX(2,start)));
+ /*printf("%f %f %d\n", mean_diff, max_diff, count);*/
+ return mean_diff > GCONST(1.f);
+}
+
+/** Apply window and compute the MDCT for all sub-frames and
+ all channels in a frame */
+static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in,
+ celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample,
+ int arch)
+{
+ const int overlap = mode->overlap;
+ int N;
+ int B;
+ int shift;
+ int i, b, c;
+ if (shortBlocks)
+ {
+ B = shortBlocks;
+ N = mode->shortMdctSize;
+ shift = mode->maxLM;
+ } else {
+ B = 1;
+ N = mode->shortMdctSize<<LM;
+ shift = mode->maxLM-LM;
+ }
+ c=0; do {
+ for (b=0;b<B;b++)
+ {
+ /* Interleaving the sub-frames while doing the MDCTs */
+ clt_mdct_forward(&mode->mdct, in+c*(B*N+overlap)+b*N,
+ &out[b+c*N*B], mode->window, overlap, shift, B,
+ arch);
+ }
+ } while (++c<CC);
+ if (CC==2&&C==1)
+ {
+ for (i=0;i<B*N;i++)
+ out[i] = ADD32(HALF32(out[i]), HALF32(out[B*N+i]));
+ }
+ if (upsample != 1)
+ {
+ c=0; do
+ {
+ int bound = B*N/upsample;
+ for (i=0;i<bound;i++)
+ out[c*B*N+i] *= upsample;
+ OPUS_CLEAR(&out[c*B*N+bound], B*N-bound);
+ } while (++c<C);
+ }
+}
+
+
+void celt_preemphasis(const opus_res * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+ int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip)
+{
+ int i;
+ opus_val16 coef0;
+ celt_sig m;
+ int Nu;
+
+ coef0 = coef[0];
+ m = *mem;
+
+ /* Fast path for the normal 48kHz case and no clipping */
+ if (coef[1] == 0 && upsample == 1 && !clip)
+ {
+ for (i=0;i<N;i++)
+ {
+ celt_sig x;
+ x = RES2SIG(pcmp[CC*i]);
+ /* Apply pre-emphasis */
+ inp[i] = x - m;
+ m = MULT16_32_Q15(coef0, x);
+ }
+ *mem = m;
+ return;
+ }
+
+ Nu = N/upsample;
+ if (upsample!=1)
+ {
+ OPUS_CLEAR(inp, N);
+ }
+ for (i=0;i<Nu;i++)
+ inp[i*upsample] = RES2SIG(pcmp[CC*i]);
+
+#ifndef FIXED_POINT
+ if (clip)
+ {
+ /* Clip input to avoid encoding non-portable files */
+ for (i=0;i<Nu;i++)
+ inp[i*upsample] = MAX32(-65536.f, MIN32(65536.f,inp[i*upsample]));
+ }
+#elif defined(ENABLE_RES24)
+ if (clip)
+ {
+ /* Clip input to avoid encoding non-portable files */
+ for (i=0;i<Nu;i++)
+ inp[i*upsample] = MAX32(-(65536<<SIG_SHIFT), MIN32(65536<<SIG_SHIFT,inp[i*upsample]));
+ }
+#else
+ (void)clip; /* Avoids a warning about clip being unused. */
+#endif
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API) || defined(ENABLE_QEXT)
+ if (coef[1] != 0)
+ {
+ opus_val16 coef1 = coef[1];
+#if defined(FIXED_POINT) && defined(ENABLE_QEXT)
+ /* If we need the extra precision, we use the fact that coef[3] is exact to do a Newton-Raphson
+ iteration and get us more precision on coef[2]. */
+ opus_val32 coef2_q30 = SHL32(coef[2], 18) + PSHR32(MULT16_16(QCONST32(1.f, 25) - MULT16_16(coef[3], coef[2]), coef[2]), 7);
+ celt_assert(SIG_SHIFT == 12);
+#else
+ opus_val16 coef2 = coef[2];
+#endif
+ for (i=0;i<N;i++)
+ {
+ celt_sig x, tmp;
+ x = inp[i];
+ /* Apply pre-emphasis */
+#if defined(FIXED_POINT) && defined(ENABLE_QEXT)
+ tmp = SHL32(MULT32_32_Q31(coef2_q30, x), 1);
+#else
+ tmp = SHL32(MULT16_32_Q15(coef2, x), 15-SIG_SHIFT);
+#endif
+ inp[i] = tmp + m;
+ m = MULT16_32_Q15(coef1, inp[i]) - MULT16_32_Q15(coef0, tmp);
+ }
+ } else
+#endif
+ {
+ for (i=0;i<N;i++)
+ {
+ celt_sig x;
+ x = inp[i];
+ /* Apply pre-emphasis */
+ inp[i] = x - m;
+ m = MULT16_32_Q15(coef0, x);
+ }
+ }
+ *mem = m;
+}
+
+
+
+static opus_val32 l1_metric(const celt_norm *tmp, int N, int LM, opus_val16 bias)
+{
+ int i;
+ opus_val32 L1;
+ L1 = 0;
+ for (i=0;i<N;i++)
+ L1 += EXTEND32(ABS16(SHR32(tmp[i], NORM_SHIFT-14)));
+ /* When in doubt, prefer good freq resolution */
+ L1 = MAC16_32_Q15(L1, LM*bias, L1);
+ return L1;
+
+}
+
+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 i;
+ VARDECL(int, metric);
+ int cost0;
+ int cost1;
+ VARDECL(int, path0);
+ VARDECL(int, path1);
+ VARDECL(celt_norm, tmp);
+ VARDECL(celt_norm, tmp_1);
+ int sel;
+ int selcost[2];
+ int tf_select=0;
+ opus_val16 bias;
+
+ SAVE_STACK;
+ bias = MULT16_16_Q14(QCONST16(.04f,15), MAX16(-QCONST16(.25f,14), QCONST16(.5f,14)-tf_estimate));
+ /*printf("%f ", bias);*/
+
+ ALLOC(metric, len, int);
+ ALLOC(tmp, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+ ALLOC(tmp_1, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+ ALLOC(path0, len, int);
+ ALLOC(path1, len, int);
+
+ for (i=0;i<len;i++)
+ {
+ int k, N;
+ int narrow;
+ opus_val32 L1, best_L1;
+ int best_level=0;
+ N = (m->eBands[i+1]-m->eBands[i])<<LM;
+ /* band is too narrow to be split down to LM=-1 */
+ narrow = (m->eBands[i+1]-m->eBands[i])==1;
+ OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<<LM)], N);
+ /* Just add the right channel if we're in stereo */
+ /*if (C==2)
+ for (j=0;j<N;j++)
+ tmp[j] = ADD16(SHR16(tmp[j], 1),SHR16(X[N0+j+(m->eBands[i]<<LM)], 1));*/
+ L1 = l1_metric(tmp, N, isTransient ? LM : 0, bias);
+ best_L1 = L1;
+ /* Check the -1 case for transients */
+ if (isTransient && !narrow)
+ {
+ OPUS_COPY(tmp_1, tmp, N);
+ haar1(tmp_1, N>>LM, 1<<LM);
+ L1 = l1_metric(tmp_1, N, LM+1, bias);
+ if (L1<best_L1)
+ {
+ best_L1 = L1;
+ best_level = -1;
+ }
+ }
+ /*printf ("%f ", L1);*/
+ for (k=0;k<LM+!(isTransient||narrow);k++)
+ {
+ int B;
+
+ if (isTransient)
+ B = (LM-k-1);
+ else
+ B = k+1;
+
+ haar1(tmp, N>>k, 1<<k);
+
+ L1 = l1_metric(tmp, N, B, bias);
+
+ if (L1 < best_L1)
+ {
+ best_L1 = L1;
+ best_level = k+1;
+ }
+ }
+ /*printf ("%d ", isTransient ? LM-best_level : best_level);*/
+ /* metric is in Q1 to be able to select the mid-point (-0.5) for narrower bands */
+ if (isTransient)
+ metric[i] = 2*best_level;
+ else
+ metric[i] = -2*best_level;
+ /* 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("\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);
+ 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 = IMIN(cost0, cost1);
+ selcost[sel]=cost0;
+ }
+ /* For now, we're conservative and only allow tf_select=1 for transients.
+ * 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);
+ /* Viterbi forward pass */
+ for (i=1;i<len;i++)
+ {
+ int curr0, curr1;
+ int from0, from1;
+
+ from0 = cost0;
+ from1 = cost1 + lambda;
+ if (from0 < from1)
+ {
+ curr0 = from0;
+ path0[i]= 0;
+ } else {
+ curr0 = from1;
+ path0[i]= 1;
+ }
+
+ from0 = cost0 + lambda;
+ from1 = cost1;
+ if (from0 < from1)
+ {
+ curr1 = from0;
+ path1[i]= 0;
+ } else {
+ curr1 = from1;
+ path1[i]= 1;
+ }
+ cost0 = curr0 + 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]);
+ }
+ tf_res[len-1] = cost0 < cost1 ? 0 : 1;
+ /* Viterbi backward pass to check the decisions */
+ for (i=len-2;i>=0;i--)
+ {
+ if (tf_res[i+1] == 1)
+ tf_res[i] = path1[i+1];
+ else
+ tf_res[i] = path0[i+1];
+ }
+ /*printf("%d %f\n", *tf_sum, tf_estimate);*/
+ RESTORE_STACK;
+#ifdef FUZZING
+ tf_select = rand()&0x1;
+ tf_res[0] = rand()&0x1;
+ for (i=1;i<len;i++)
+ tf_res[i] = tf_res[i-1] ^ ((rand()&0xF) == 0);
+#endif
+ return tf_select;
+}
+
+static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM, int tf_select, ec_enc *enc)
+{
+ int curr, i;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ opus_uint32 budget;
+ opus_uint32 tell;
+ budget = enc->storage*8;
+ tell = ec_tell(enc);
+ logp = isTransient ? 2 : 4;
+ /* Reserve space to code the tf_select decision. */
+ tf_select_rsv = LM>0 && tell+logp+1 <= budget;
+ budget -= tf_select_rsv;
+ curr = tf_changed = 0;
+ for (i=start;i<end;i++)
+ {
+ if (tell+logp<=budget)
+ {
+ ec_enc_bit_logp(enc, tf_res[i] ^ curr, logp);
+ tell = ec_tell(enc);
+ curr = tf_res[i];
+ tf_changed |= curr;
+ }
+ else
+ tf_res[i] = curr;
+ logp = isTransient ? 4 : 5;
+ }
+ /* Only code tf_select if it would actually make a difference. */
+ if (tf_select_rsv &&
+ tf_select_table[LM][4*isTransient+0+tf_changed]!=
+ tf_select_table[LM][4*isTransient+2+tf_changed])
+ ec_enc_bit_logp(enc, tf_select, 1);
+ else
+ tf_select = 0;
+ for (i=start;i<end;i++)
+ tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+ /*for(i=0;i<end;i++)printf("%d ", isTransient ? tf_res[i] : LM+tf_res[i]);printf("\n");*/
+}
+
+
+static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
+ const celt_glog *bandLogE, int end, int LM, int C, int N0,
+ AnalysisInfo *analysis, opus_val16 *stereo_saving, opus_val16 tf_estimate,
+ int intensity, celt_glog surround_trim, opus_int32 equiv_rate, int arch)
+{
+ int i;
+ opus_val32 diff=0;
+ int c;
+ 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 */
+ opus_val16 minXC; /* Q10 */
+ /* Compute inter-channel correlation for low frequencies */
+ for (i=0;i<8;i++)
+ {
+ opus_val32 partial;
+ partial = celt_inner_prod_norm_shift(&X[m->eBands[i]<<LM], &X[N0+(m->eBands[i]<<LM)],
+ (m->eBands[i+1]-m->eBands[i])<<LM, arch);
+ sum = ADD16(sum, EXTRACT16(SHR32(partial, 18)));
+ }
+ sum = MULT16_16_Q15(QCONST16(1.f/8, 15), sum);
+ sum = MIN16(QCONST16(1.f, 10), ABS16(sum));
+ minXC = sum;
+ for (i=8;i<intensity;i++)
+ {
+ opus_val32 partial;
+ partial = celt_inner_prod_norm_shift(&X[m->eBands[i]<<LM], &X[N0+(m->eBands[i]<<LM)],
+ (m->eBands[i+1]-m->eBands[i])<<LM, arch);
+ minXC = MIN16(minXC, ABS16(EXTRACT16(SHR32(partial, 18))));
+ }
+ minXC = MIN16(QCONST16(1.f, 10), ABS16(minXC));
+ /*printf ("%f\n", sum);*/
+ /* mid-side savings estimations based on the LF average*/
+ logXC = celt_log2(QCONST32(1.001f, 20)-MULT16_16(sum, sum));
+ /* mid-side savings estimations based on min correlation */
+ logXC2 = MAX16(HALF16(logXC), celt_log2(QCONST32(1.001f, 20)-MULT16_16(minXC, minXC)));
+#ifdef FIXED_POINT
+ /* Compensate for Q20 vs Q14 input and convert output to Q8 */
+ logXC = PSHR32(logXC-QCONST16(6.f, 10),10-8);
+ logXC2 = PSHR32(logXC2-QCONST16(6.f, 10),10-8);
+#endif
+
+ trim += MAX16(-QCONST16(4.f, 8), MULT16_16_Q15(QCONST16(.75f,15),logXC));
+ *stereo_saving = MIN16(*stereo_saving + QCONST16(0.25f, 8), -HALF16(logXC2));
+ }
+
+ /* Estimate spectral tilt */
+ c=0; do {
+ for (i=0;i<end-1;i++)
+ {
+ diff += SHR32(bandLogE[i+c*m->nbEBands], 5)*(opus_int32)(2+2*i-end);
+ }
+ } while (++c<C);
+ diff /= C*(end-1);
+ /*printf("%f\n", diff);*/
+ trim -= MAX32(-QCONST16(2.f, 8), MIN32(QCONST16(2.f, 8), SHR32(diff+QCONST32(1.f, DB_SHIFT-5),DB_SHIFT-13)/6 ));
+ trim -= SHR16(surround_trim, DB_SHIFT-8);
+ trim -= 2*SHR16(tf_estimate, 14-8);
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid)
+ {
+ trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8),
+ (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f))));
+ }
+#else
+ (void)analysis;
+#endif
+
+#ifdef FIXED_POINT
+ trim_index = PSHR32(trim, 8);
+#else
+ trim_index = (int)floor(.5f+trim);
+#endif
+ trim_index = IMAX(0, IMIN(10, trim_index));
+ /*printf("%d\n", trim_index);*/
+#ifdef FUZZING
+ trim_index = rand()%11;
+#endif
+ return trim_index;
+}
+
+static int stereo_analysis(const CELTMode *m, const celt_norm *X,
+ int LM, int N0)
+{
+ int i;
+ int thetas;
+ opus_val32 sumLR = EPSILON, sumMS = EPSILON;
+
+ /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */
+ for (i=0;i<13;i++)
+ {
+ int j;
+ for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+ {
+ opus_val32 L, R, M, S;
+ /* We cast to 32-bit first because of the -32768 case */
+ L = SHR32(X[j], NORM_SHIFT-14);
+ R = SHR32(X[N0+j], NORM_SHIFT-14);
+ M = ADD32(L, R);
+ S = SUB32(L, R);
+ sumLR = ADD32(sumLR, ADD32(ABS32(L), ABS32(R)));
+ sumMS = ADD32(sumMS, ADD32(ABS32(M), ABS32(S)));
+ }
+ }
+ sumMS = MULT16_32_Q15(QCONST16(0.707107f, 15), sumMS);
+ thetas = 13;
+ /* We don't need thetas for lower bands with LM<=1 */
+ if (LM<=1)
+ thetas -= 8;
+ return MULT16_32_Q15((m->eBands[13]<<(LM+1))+thetas, sumMS)
+ > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
+}
+
+#define MSWAP(a,b) do {celt_glog tmp = a;a=b;b=tmp;} while(0)
+static celt_glog median_of_5(const celt_glog *x)
+{
+ celt_glog t0, t1, t2, t3, t4;
+ t2 = x[2];
+ if (x[0] > x[1])
+ {
+ t0 = x[1];
+ t1 = x[0];
+ } else {
+ t0 = x[0];
+ t1 = x[1];
+ }
+ if (x[3] > x[4])
+ {
+ t3 = x[4];
+ t4 = x[3];
+ } else {
+ t3 = x[3];
+ t4 = x[4];
+ }
+ if (t0 > t3)
+ {
+ MSWAP(t0, t3);
+ MSWAP(t1, t4);
+ }
+ if (t2 > t1)
+ {
+ if (t1 < t3)
+ return MING(t2, t3);
+ else
+ return MING(t4, t1);
+ } else {
+ if (t2 < t3)
+ return MING(t1, t3);
+ else
+ return MING(t2, t4);
+ }
+}
+
+static celt_glog median_of_3(const celt_glog *x)
+{
+ celt_glog t0, t1, t2;
+ if (x[0] > x[1])
+ {
+ t0 = x[1];
+ t1 = x[0];
+ } else {
+ t0 = x[0];
+ t1 = x[1];
+ }
+ t2 = x[2];
+ if (t1 < t2)
+ return t1;
+ else if (t0 < t2)
+ return t2;
+ else
+ return t0;
+}
+
+static celt_glog dynalloc_analysis(const celt_glog *bandLogE, const celt_glog *bandLogE2, const celt_glog *oldBandE,
+ 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, celt_glog *surround_dynalloc,
+ AnalysisInfo *analysis, int *importance, int *spread_weight, opus_val16 tone_freq, opus_val32 toneishness
+ ARG_QEXT(int qext_scale))
+{
+ int i, c;
+ opus_int32 tot_boost=0;
+ celt_glog maxDepth;
+ VARDECL(celt_glog, follower);
+ VARDECL(celt_glog, noise_floor);
+ VARDECL(celt_glog, bandLogE3);
+ SAVE_STACK;
+ ALLOC(follower, C*nbEBands, celt_glog);
+ ALLOC(noise_floor, C*nbEBands, celt_glog);
+ ALLOC(bandLogE3, nbEBands, celt_glog);
+ OPUS_CLEAR(offsets, nbEBands);
+ /* Dynamic allocation code */
+ maxDepth=-GCONST(31.9f);
+ for (i=0;i<end;i++)
+ {
+ /* Noise floor must take into account eMeans, the depth, the width of the bands
+ and the preemphasis filter (approx. square of bark band ID) */
+ noise_floor[i] = GCONST(0.0625f)*logN[i]
+ +GCONST(.5f)+SHL32(9-lsb_depth,DB_SHIFT)-SHL32(eMeans[i],DB_SHIFT-4)
+ +GCONST(.0062f)*(i+5)*(i+5);
+ }
+ c=0;do
+ {
+ for (i=0;i<end;i++)
+ maxDepth = MAXG(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(celt_glog, mask);
+ VARDECL(celt_glog, sig);
+ ALLOC(mask, nbEBands, celt_glog);
+ ALLOC(sig, nbEBands, celt_glog);
+ for (i=0;i<end;i++)
+ mask[i] = bandLogE[i]-noise_floor[i];
+ if (C==2)
+ {
+ for (i=0;i<end;i++)
+ mask[i] = MAXG(mask[i], bandLogE[nbEBands+i]-noise_floor[i]);
+ }
+ OPUS_COPY(sig, mask, end);
+ for (i=1;i<end;i++)
+ mask[i] = MAXG(mask[i], mask[i-1] - GCONST(2.f));
+ for (i=end-2;i>=0;i--)
+ mask[i] = MAXG(mask[i], mask[i+1] - GCONST(3.f));
+ for (i=0;i<end;i++)
+ {
+ /* Compute SMR: Mask is never more than 72 dB below the peak and never below the noise floor.*/
+ celt_glog smr = sig[i]-MAXG(MAXG(0, maxDepth-GCONST(12.f)), 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(MAXG(-GCONST(5.f), MING(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.
+ We enable the feature starting at 24 kb/s for 20-ms frames
+ and 96 kb/s for 2.5 ms frames. */
+ if (effectiveBytes >= (30 + 5*LM) && !lfe)
+ {
+ int last=0;
+ c=0;do
+ {
+ celt_glog offset;
+ celt_glog tmp;
+ celt_glog *f;
+ OPUS_COPY(bandLogE3, &bandLogE2[c*nbEBands], end);
+ if (LM==0) {
+ /* For 2.5 ms frames, the first 8 bands have just one bin, so the
+ energy is highly unreliable (high variance). For that reason,
+ we take the max with the previous energy so that at least 2 bins
+ are getting used. */
+ for (i=0;i<IMIN(8,end);i++) bandLogE3[i] = MAXG(bandLogE2[c*nbEBands+i], oldBandE[c*nbEBands+i]);
+ }
+ f = &follower[c*nbEBands];
+ f[0] = bandLogE3[0];
+ for (i=1;i<end;i++)
+ {
+ /* The last band to be at least 3 dB higher than the previous one
+ is the last we'll consider. Otherwise, we run into problems on
+ bandlimited signals. */
+ if (bandLogE3[i] > bandLogE3[i-1]+GCONST(.5f))
+ last=i;
+ f[i] = MING(f[i-1]+GCONST(1.5f), bandLogE3[i]);
+ }
+ for (i=last-1;i>=0;i--)
+ f[i] = MING(f[i], MING(f[i+1]+GCONST(2.f), bandLogE3[i]));
+
+ /* Combine with a median filter to avoid dynalloc triggering unnecessarily.
+ The "offset" value controls how conservative we are -- a higher offset
+ reduces the impact of the median filter and makes dynalloc use more bits. */
+ offset = GCONST(1.f);
+ for (i=2;i<end-2;i++)
+ f[i] = MAXG(f[i], median_of_5(&bandLogE3[i-2])-offset);
+ tmp = median_of_3(&bandLogE3[0])-offset;
+ f[0] = MAXG(f[0], tmp);
+ f[1] = MAXG(f[1], tmp);
+ tmp = median_of_3(&bandLogE3[end-3])-offset;
+ f[end-2] = MAXG(f[end-2], tmp);
+ f[end-1] = MAXG(f[end-1], tmp);
+
+ for (i=0;i<end;i++)
+ f[i] = MAXG(f[i], noise_floor[i]);
+ } while (++c<C);
+ if (C==2)
+ {
+ for (i=start;i<end;i++)
+ {
+ /* Consider 24 dB "cross-talk" */
+ follower[nbEBands+i] = MAXG(follower[nbEBands+i], follower[ i]-GCONST(4.f));
+ follower[ i] = MAXG(follower[ i], follower[nbEBands+i]-GCONST(4.f));
+ follower[i] = HALF32(MAXG(0, bandLogE[i]-follower[i]) + MAXG(0, bandLogE[nbEBands+i]-follower[nbEBands+i]));
+ }
+ } else {
+ for (i=start;i<end;i++)
+ {
+ follower[i] = MAXG(0, bandLogE[i]-follower[i]);
+ }
+ }
+ for (i=start;i<end;i++)
+ follower[i] = MAXG(follower[i], surround_dynalloc[i]);
+ for (i=start;i<end;i++)
+ {
+#ifdef FIXED_POINT
+ importance[i] = PSHR32(13*celt_exp2_db(MING(follower[i], GCONST(4.f))), 16);
+#else
+ importance[i] = (int)floor(.5f+13*celt_exp2_db(MING(follower[i], GCONST(4.f))));
+#endif
+ }
+ /* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
+ if ((!vbr || constrained_vbr)&&!isTransient)
+ {
+ for (i=start;i<end;i++)
+ follower[i] = HALF32(follower[i]);
+ }
+ for (i=start;i<end;i++)
+ {
+ if (i<8)
+ follower[i] *= 2;
+ if (i>=12)
+ follower[i] = HALF32(follower[i]);
+ }
+ /* Compensate for Opus' under-allocation on tones. */
+ if (toneishness > QCONST32(.98f, 29)) {
+#ifdef FIXED_POINT
+ int freq_bin = PSHR32(QEXT_SCALE((opus_val32)tone_freq)*QCONST16(120/M_PI, 9), 13+9);
+#else
+ int freq_bin = (int)floor(.5 + QEXT_SCALE(tone_freq)*120/M_PI);
+#endif
+ for (i=start;i<end;i++) {
+ if (freq_bin >= eBands[i] && freq_bin <= eBands[i+1]) follower[i] += GCONST(2.f);
+ if (freq_bin >= eBands[i]-1 && freq_bin <= eBands[i+1]+1) follower[i] += GCONST(1.f);
+ if (freq_bin >= eBands[i]-2 && freq_bin <= eBands[i+1]+2) follower[i] += GCONST(1.f);
+ if (freq_bin >= eBands[i]-3 && freq_bin <= eBands[i+1]+3) follower[i] += GCONST(.5f);
+ }
+ if (freq_bin >= eBands[end]) {
+ follower[end-1] += GCONST(2.f);
+ follower[end-2] += GCONST(1.f);
+ }
+ }
+#ifdef DISABLE_FLOAT_API
+ (void)analysis;
+#else
+ if (analysis->valid)
+ {
+ for (i=start;i<IMIN(LEAK_BANDS, end);i++)
+ follower[i] = follower[i] + GCONST(1.f/64.f)*analysis->leak_boost[i];
+ }
+#endif
+ for (i=start;i<end;i++)
+ {
+ int width;
+ int boost;
+ int boost_bits;
+
+ follower[i] = MING(follower[i], GCONST(4));
+
+ follower[i] = SHR32(follower[i], 8);
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ if (width<6)
+ {
+ boost = (int)SHR32(follower[i],DB_SHIFT-8);
+ boost_bits = boost*width<<BITRES;
+ } else if (width > 48) {
+ boost = (int)SHR32(follower[i]*8,DB_SHIFT-8);
+ boost_bits = (boost*width<<BITRES)/8;
+ } else {
+ boost = (int)SHR32(follower[i]*width/6,DB_SHIFT-8);
+ boost_bits = boost*6<<BITRES;
+ }
+ /* For CBR and non-transient CVBR frames, limit dynalloc to 2/3 of the bits */
+ if ((!vbr || (constrained_vbr&&!isTransient))
+ && (tot_boost+boost_bits)>>BITRES>>3 > 2*effectiveBytes/3)
+ {
+ opus_int32 cap = ((2*effectiveBytes/3)<<BITRES<<3);
+ offsets[i] = cap-tot_boost;
+ tot_boost = cap;
+ break;
+ } else {
+ offsets[i] = boost;
+ tot_boost += boost_bits;
+ }
+ }
+ } else {
+ for (i=start;i<end;i++)
+ importance[i] = 13;
+ }
+ *tot_boost_ = tot_boost;
+ RESTORE_STACK;
+ return maxDepth;
+}
+
+#ifdef FIXED_POINT
+void normalize_tone_input(opus_val16 *x, int len) {
+ opus_val32 ac0=len;
+ int i;
+ int shift;
+ for (i=0;i<len;i++) {
+ ac0 = ADD32(ac0, SHR32(MULT16_16(x[i], x[i]), 10));
+ }
+ shift = 5 - (28-celt_ilog2(ac0))/2;
+ if (shift > 0) {
+ for (i=0;i<len;i++) {
+ x[i] = PSHR32(x[i], shift);
+ }
+ }
+}
+int acos_approx(opus_val32 x) {
+ opus_val16 x14;
+ opus_val32 tmp;
+ int flip = x<0;
+ x = abs(x);
+ x14 = x>>15;
+ tmp = (762*x14>>14)-3308;
+ tmp = (tmp*x14>>14)+25726;
+ tmp = tmp*celt_sqrt(IMAX(0, (1<<30) - (x<<1)))>>16;
+ if (flip) tmp = 25736 - tmp;
+ return tmp;
+}
+#endif
+
+/* Compute the LPC coefficients using a least-squares fit for both forward and backward prediction. */
+static int tone_lpc(const opus_val16 *x, int len, int delay, opus_val32 *lpc) {
+ int i;
+ opus_val32 r00=0, r01=0, r11=0, r02=0, r12=0, r22=0;
+ opus_val32 edges;
+ opus_val32 num0, num1, den;
+ celt_assert(len > 2*delay);
+ /* Compute correlations as if using the forward prediction covariance method. */
+ for (i=0;i<len-2*delay;i++) {
+ r00 += MULT16_16(x[i],x[i]);
+ r01 += MULT16_16(x[i],x[i+delay]);
+ r02 += MULT16_16(x[i],x[i+2*delay]);
+ }
+ edges = 0;
+ for (i=0;i<delay;i++) edges += MULT16_16(x[len+i-2*delay],x[len+i-2*delay]) - MULT16_16(x[i],x[i]);
+ r11 = r00+edges;
+ edges = 0;
+ for (i=0;i<delay;i++) edges += MULT16_16(x[len+i-delay],x[len+i-delay]) - MULT16_16(x[i+delay],x[i+delay]);
+ r22 = r11+edges;
+ edges = 0;
+ for (i=0;i<delay;i++) edges += MULT16_16(x[len+i-2*delay],x[len+i-delay]) - MULT16_16(x[i],x[i+delay]);
+ r12 = r01+edges;
+ /* Reverse and sum to get the backward contribution. */
+ {
+ opus_val32 R00, R01, R11, R02, R12, R22;
+ R00 = r00 + r22;
+ R01 = r01 + r12;
+ R11 = 2*r11;
+ R02 = 2*r02;
+ R12 = r12 + r01;
+ R22 = r00 + r22;
+ r00 = R00;
+ r01 = R01;
+ r11 = R11;
+ r02 = R02;
+ r12 = R12;
+ r22 = R22;
+ }
+ /* Solve A*x=b, where A=[r00, r01; r01, r11] and b=[r02; r12]. */
+ den = MULT32_32_Q31(r00,r11) - MULT32_32_Q31(r01,r01);
+#ifdef FIXED_POINT
+ if (den <= SHR32(MULT32_32_Q31(r00,r11), 10)) return 1;
+#else
+ if (den < .001f*MULT32_32_Q31(r00,r11)) return 1;
+#endif
+ num1 = MULT32_32_Q31(r02,r11) - MULT32_32_Q31(r01,r12);
+ if (num1 >= den) lpc[1] = QCONST32(1.f, 29);
+ else if (num1 <= -den) lpc[1] = -QCONST32(1.f, 29);
+ else lpc[1] = frac_div32_q29(num1, den);
+ num0 = MULT32_32_Q31(r00,r12) - MULT32_32_Q31(r02,r01);
+ if (HALF32(num0) >= den) lpc[0] = QCONST32(1.999999f, 29);
+ else if (HALF32(num0) <= -den) lpc[0] = -QCONST32(1.999999f, 29);
+ else lpc[0] = frac_div32_q29(num0, den);
+ /*printf("%f %f\n", lpc[0], lpc[1]);*/
+ return 0;
+}
+
+/* Detects pure of nearly pure tones so we can prevent them from causing problems with the encoder. */
+static opus_val16 tone_detect(const celt_sig *in, int CC, int N, opus_val32 *toneishness, opus_int32 Fs) {
+ int i;
+ int delay = 1;
+ int fail;
+ opus_val32 lpc[2];
+ opus_val16 freq;
+ VARDECL(opus_val16, x);
+ SAVE_STACK;
+ ALLOC(x, N, opus_val16);
+ /* Shift by SIG_SHIFT+2 (+3 for stereo) to account for HF gain of the preemphasis filter. */
+ if (CC==2) {
+ for (i=0;i<N;i++) x[i] = PSHR32(ADD32(SHR32(in[i], 1), SHR32(in[i+N], 1)), SIG_SHIFT+2);
+ } else {
+ for (i=0;i<N;i++) x[i] = PSHR32(in[i], SIG_SHIFT+2);
+ }
+#ifdef FIXED_POINT
+ normalize_tone_input(x, N);
+#endif
+ fail = tone_lpc(x, N, delay, lpc);
+ /* If our LPC filter resonates too close to DC, retry the analysis with down-sampling. */
+ while (delay <= Fs/3000 && (fail || (lpc[0] > QCONST32(1.f, 29) && lpc[1] < 0))) {
+ delay *= 2;
+ fail = tone_lpc(x, N, delay, lpc);
+ }
+ /* Check that our filter has complex roots. */
+ if (!fail && MULT32_32_Q31(lpc[0],lpc[0]) + MULT32_32_Q31(QCONST32(3.999999, 29), lpc[1]) < 0) {
+ /* Squared radius of the poles. */
+ *toneishness = -lpc[1];
+#ifdef FIXED_POINT
+ freq = (acos_approx(lpc[0]>>1)+delay/2)/delay;
+#else
+ freq = acos(.5f*lpc[0])/delay;
+#endif
+ } else {
+ freq = -1;
+ *toneishness=0;
+ }
+ /*printf("%f %f %f %f\n", freq, lpc[0], lpc[1], *toneishness);*/
+ RESTORE_STACK;
+ return freq;
+}
+
+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 complexity, opus_val16 tf_estimate,
+ int nbAvailableBytes, AnalysisInfo *analysis, opus_val16 tone_freq, opus_val32 toneishness ARG_QEXT(int qext_scale))
+{
+ int c;
+ VARDECL(celt_sig, _pre);
+ celt_sig *pre[2];
+ const CELTMode *mode;
+ int pitch_index;
+ opus_val16 gain1;
+ opus_val16 pf_threshold;
+ int pf_on;
+ int qg;
+ int overlap;
+ int min_period, max_period;
+ opus_val32 before[2]={0}, after[2]={0};
+ int cancel_pitch=0;
+ SAVE_STACK;
+
+ max_period = QEXT_SCALE(COMBFILTER_MAXPERIOD);
+ min_period = QEXT_SCALE(COMBFILTER_MINPERIOD);
+ mode = st->mode;
+ overlap = mode->overlap;
+ ALLOC(_pre, CC*(N+max_period), celt_sig);
+
+ pre[0] = _pre;
+ pre[1] = _pre + (N+max_period);
+
+
+ c=0; do {
+ OPUS_COPY(pre[c], prefilter_mem+c*max_period, max_period);
+ OPUS_COPY(pre[c]+max_period, in+c*(N+overlap)+overlap, N);
+ } while (++c<CC);
+
+ /* If we detect that the signal is dominated by a single tone, don't rely on the standard pitch
+ estimator, as it can become unreliable. */
+ if (enabled && toneishness > QCONST32(.99f, 29)) {
+ int multiple=1;
+ /* Using aliased version of the postfilter above 24 kHz.
+ First value is purposely slightly above pi to avoid triggering for Fs=48kHz. */
+ if (QEXT_SCALE(tone_freq) >= QCONST16(3.1416f, 13)) tone_freq = QCONST16(3.141593f, 13) - tone_freq;
+ /* If the pitch is too high for our post-filter, apply pitch doubling until
+ we can get something that fits (not ideal, but better than nothing). */
+ while (QEXT_SCALE(tone_freq) >= multiple*QCONST16(0.39f, 13)) multiple++;
+ if (QEXT_SCALE(tone_freq) > QCONST16(0.006148f, 13)) {
+#ifdef FIXED_POINT
+ pitch_index = IMIN((51472*multiple+QEXT_SCALE(tone_freq)/2)/QEXT_SCALE(tone_freq), COMBFILTER_MAXPERIOD-2);
+#else
+ pitch_index = IMIN((int)floor(.5+2.f*M_PI*multiple/QEXT_SCALE(tone_freq)), COMBFILTER_MAXPERIOD-2);
+#endif
+ } else {
+ /* If the pitch is too low, using a very high pitch will actually give us an improvement
+ due to the DC component of the filter that will be close to our tone. Again, not ideal,
+ but if we only have a single tone, it's better than nothing. */
+ pitch_index = COMBFILTER_MINPERIOD;
+ }
+ gain1 = QCONST16(.75f, 15);
+ } else if (enabled && complexity >= 5) {
+ VARDECL(opus_val16, pitch_buf);
+ ALLOC(pitch_buf, (max_period+N)>>1, opus_val16);
+
+ pitch_downsample(pre, pitch_buf, (max_period+N)>>1, CC, 2, st->arch);
+ /* Don't search for the fir last 1.5 octave of the range because
+ there's too many false-positives due to short-term correlation */
+ pitch_search(pitch_buf+(max_period>>1), pitch_buf, N,
+ max_period-3*min_period, &pitch_index,
+ st->arch);
+ pitch_index = max_period-pitch_index;
+
+ gain1 = remove_doubling(pitch_buf, max_period, min_period,
+ N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch);
+ if (pitch_index > max_period-QEXT_SCALE(2))
+ pitch_index = max_period-QEXT_SCALE(2);
+#ifdef ENABLE_QEXT
+ pitch_index /= qext_scale;
+#endif
+ gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1);
+ /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/
+ if (st->loss_rate>2)
+ gain1 = HALF32(gain1);
+ if (st->loss_rate>4)
+ gain1 = HALF32(gain1);
+ if (st->loss_rate>8)
+ gain1 = 0;
+ } else {
+ gain1 = 0;
+ pitch_index = COMBFILTER_MINPERIOD;
+ }
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid)
+ gain1 = (opus_val16)(gain1 * analysis->max_pitch_ratio);
+#else
+ (void)analysis;
+#endif
+ /* Gain threshold for enabling the prefilter/postfilter */
+ pf_threshold = QCONST16(.2f,15);
+
+ /* Adjusting the threshold based on rate and continuity */
+ if (abs(pitch_index-st->prefilter_period)*10>pitch_index)
+ {
+ pf_threshold += QCONST16(.2f,15);
+ /* Completely disable the prefilter on strong transients without continuity. */
+ if (tf_estimate > QCONST16(.98f, 14))
+ gain1 = 0;
+ }
+ if (nbAvailableBytes<25)
+ pf_threshold += QCONST16(.1f,15);
+ if (nbAvailableBytes<35)
+ pf_threshold += QCONST16(.1f,15);
+ if (st->prefilter_gain > QCONST16(.4f,15))
+ pf_threshold -= QCONST16(.1f,15);
+ if (st->prefilter_gain > QCONST16(.55f,15))
+ pf_threshold -= QCONST16(.1f,15);
+
+ /* Hard threshold at 0.2 */
+ pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15));
+ if (gain1<pf_threshold)
+ {
+ gain1 = 0;
+ pf_on = 0;
+ qg = 0;
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ if (ABS16(gain1-st->prefilter_gain)<QCONST16(.1f,15))
+ gain1=st->prefilter_gain;
+
+#ifdef FIXED_POINT
+ qg = ((gain1+1536)>>10)/3-1;
+#else
+ qg = (int)floor(.5f+gain1*32/3)-1;
+#endif
+ qg = IMAX(0, IMIN(7, qg));
+ gain1 = QCONST16(0.09375f,15)*(qg+1);
+ pf_on = 1;
+ }
+ /*printf("%d %f\n", pitch_index, gain1);*/
+
+ c=0; do {
+ int i;
+ int offset = mode->shortMdctSize-overlap;
+ st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+ OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap);
+ for (i=0;i<N;i++) before[c] += ABS32(SHR32(in[c*(N+overlap)+overlap+i], 12));
+ if (offset)
+ comb_filter(in+c*(N+overlap)+overlap, pre[c]+max_period,
+ st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain,
+ st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch);
+
+ comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+max_period+offset,
+ st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1,
+ st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch);
+ for (i=0;i<N;i++) after[c] += ABS32(SHR32(in[c*(N+overlap)+overlap+i], 12));
+ } while (++c<CC);
+
+ if (CC==2) {
+ opus_val16 thresh[2];
+ thresh[0] = MULT16_32_Q15(MULT16_16_Q15(QCONST16(.25f, 15), gain1), before[0]) + MULT16_32_Q15(QCONST16(.01f,15), before[1]);
+ thresh[1] = MULT16_32_Q15(MULT16_16_Q15(QCONST16(.25f, 15), gain1), before[1]) + MULT16_32_Q15(QCONST16(.01f,15), before[0]);
+ /* Don't use the filter if one channel gets significantly worse. */
+ if (after[0]-before[0] > thresh[0] || after[1]-before[1] > thresh[1]) cancel_pitch = 1;
+ /* Use the filter only if at least one channel gets significantly better. */
+ if (before[0]-after[0] < thresh[0] && before[1]-after[1] < thresh[1]) cancel_pitch = 1;
+ } else {
+ /* Check that the mono channel actually got better. */
+ if (after[0] > before[0]) cancel_pitch = 1;
+ }
+ /* If needed, revert to a gain of zero. */
+ if (cancel_pitch) {
+ c=0; do {
+ int offset = mode->shortMdctSize-overlap;
+ OPUS_COPY(in+c*(N+overlap)+overlap, pre[c]+max_period, N);
+ comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+max_period+offset,
+ st->prefilter_period, pitch_index, overlap, -st->prefilter_gain, -0,
+ st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch);
+ } while (++c<CC);
+ gain1 = 0;
+ pf_on = 0;
+ qg = 0;
+ }
+
+ c=0; do {
+ OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap);
+
+ if (N>max_period)
+ {
+ OPUS_COPY(prefilter_mem+c*max_period, pre[c]+N, max_period);
+ } else {
+ OPUS_MOVE(prefilter_mem+c*max_period, prefilter_mem+c*max_period+N, max_period-N);
+ OPUS_COPY(prefilter_mem+c*max_period+max_period-N, pre[c]+max_period, N);
+ }
+ } while (++c<CC);
+
+ RESTORE_STACK;
+ *gain = gain1;
+ *pitch = pitch_index;
+ *qgain = qg;
+ return pf_on;
+}
+
+static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 base_target,
+ 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, celt_glog maxDepth,
+ int lfe, int has_surround_mask, celt_glog surround_masking,
+ celt_glog temporal_vbr ARG_QEXT(int enable_qext))
+{
+ /* The target rate in 8th bits per frame */
+ opus_int32 target;
+ int coded_bins;
+ int coded_bands;
+ opus_val16 tf_calibration;
+ int nbEBands;
+ const opus_int16 *eBands;
+
+ nbEBands = mode->nbEBands;
+ eBands = mode->eBands;
+
+ coded_bands = lastCodedBands ? lastCodedBands : nbEBands;
+ coded_bins = eBands[coded_bands]<<LM;
+ if (C==2)
+ coded_bins += eBands[IMIN(intensity, coded_bands)]<<LM;
+
+ target = base_target;
+
+ /*printf("%f %f %f %f %d %d ", st->analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid && analysis->activity<.4)
+ target -= (opus_int32)((coded_bins<<BITRES)*(.4f-analysis->activity));
+#endif
+ /* Stereo savings */
+ if (C==2)
+ {
+ int coded_stereo_bands;
+ int coded_stereo_dof;
+ opus_val16 max_frac;
+ coded_stereo_bands = IMIN(intensity, coded_bands);
+ coded_stereo_dof = (eBands[coded_stereo_bands]<<LM)-coded_stereo_bands;
+ /* Maximum fraction of the bits we can save if the signal is mono. */
+ max_frac = DIV32_16(MULT16_16(QCONST16(0.8f, 15), coded_stereo_dof), coded_bins);
+ stereo_saving = MIN16(stereo_saving, QCONST16(1.f, 8));
+ /*printf("%d %d %d ", coded_stereo_dof, coded_bins, tot_boost);*/
+ target -= (opus_int32)MIN32(MULT16_32_Q15(max_frac,target),
+ 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);
+ /* Apply transient boost, compensating for average boost. */
+ tf_calibration = QCONST16(0.044f,14);
+ target += (opus_int32)SHL32(MULT16_32_Q15(tf_estimate-tf_calibration, target),1);
+
+#ifndef DISABLE_FLOAT_API
+ /* Apply tonality boost */
+ if (analysis->valid && !lfe)
+ {
+ opus_int32 tonal_target;
+ float tonal;
+
+ /* Tonality boost (compensating for the average). */
+ tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f;
+ tonal_target = target + (opus_int32)((coded_bins<<BITRES)*1.2f*tonal);
+ if (pitch_change)
+ tonal_target += (opus_int32)((coded_bins<<BITRES)*.8f);
+ /*printf("%f %f ", analysis->tonality, tonal);*/
+ target = tonal_target;
+ }
+#else
+ (void)analysis;
+ (void)pitch_change;
+#endif
+
+ if (has_surround_mask&&!lfe)
+ {
+ opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(SHR32(surround_masking,DB_SHIFT-10),coded_bins<<BITRES), 10);
+ /*printf("%f %d %d %d %d %d %d ", surround_masking, coded_bins, st->end, st->intensity, surround_target, target, st->bitrate);*/
+ target = IMAX(target/4, surround_target);
+ }
+
+ {
+ opus_int32 floor_depth;
+ int bins;
+ bins = eBands[nbEBands-2]<<LM;
+#ifdef ENABLE_QEXT
+ if (enable_qext) bins = mode->shortMdctSize<<LM;
+#endif
+ /*floor_depth = SHR32(MULT16_16((C*bins<<BITRES),celt_log2(SHL32(MAX16(1,sample_max),13))), DB_SHIFT);*/
+ floor_depth = (opus_int32)SHR32(MULT16_32_Q15((C*bins<<BITRES),maxDepth), DB_SHIFT-15);
+ floor_depth = IMAX(floor_depth, target>>2);
+ target = IMIN(target, floor_depth);
+ /*printf("%f %d\n", maxDepth, floor_depth);*/
+ }
+
+ /* Make VBR less aggressive for constrained VBR because we can't keep a higher bitrate
+ for long. Needs tuning. */
+ if ((!has_surround_mask||lfe) && constrained_vbr)
+ {
+ target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target);
+ }
+
+ if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14))
+ {
+ opus_val16 amount;
+ opus_val16 tvbr_factor;
+ amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate)));
+ tvbr_factor = SHR32(MULT16_16(SHR32(temporal_vbr, DB_SHIFT-10), amount), 10);
+ target += (opus_int32)MULT16_32_Q15(tvbr_factor, target);
+ }
+
+ /* Don't allow more than doubling the rate */
+ target = IMIN(2*base_target, target);
+
+ return target;
+}
+
+#ifdef ENABLE_QEXT
+static void encode_qext_stereo_params(ec_enc *ec, int qext_end, int qext_intensity, int qext_dual_stereo) {
+ ec_enc_uint(ec, qext_intensity, qext_end+1);
+ if (qext_intensity != 0) ec_enc_bit_logp(ec, qext_dual_stereo, 1);
+}
+#endif
+
+int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_res * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+{
+ int i, c, N;
+ opus_int32 bits;
+ ec_enc _enc;
+ VARDECL(celt_sig, in);
+ VARDECL(celt_sig, freq);
+ VARDECL(celt_norm, X);
+ VARDECL(celt_ener, bandE);
+ VARDECL(celt_glog, bandLogE);
+ VARDECL(celt_glog, bandLogE2);
+ VARDECL(int, fine_quant);
+ VARDECL(celt_glog, error);
+ VARDECL(int, pulses);
+ VARDECL(int, cap);
+ VARDECL(int, offsets);
+ VARDECL(int, importance);
+ VARDECL(int, spread_weight);
+ VARDECL(int, fine_priority);
+ VARDECL(int, tf_res);
+ VARDECL(unsigned char, collapse_masks);
+ celt_sig *prefilter_mem;
+ celt_glog *oldBandE, *oldLogE, *oldLogE2, *energyError;
+ int shortBlocks=0;
+ int isTransient=0;
+ const int CC = st->channels;
+ const int C = st->stream_channels;
+ int LM, M;
+ int tf_select;
+ int nbFilledBytes, nbAvailableBytes;
+ opus_int32 min_allowed;
+ int start;
+ int end;
+ int effEnd;
+ int codedBands;
+ int alloc_trim;
+ int pitch_index=COMBFILTER_MINPERIOD;
+ opus_val16 gain1 = 0;
+ int dual_stereo=0;
+ int effectiveBytes;
+ int dynalloc_logp;
+ opus_int32 vbr_rate;
+ opus_int32 total_bits;
+ opus_int32 total_boost;
+ opus_int32 balance;
+ opus_int32 tell;
+ opus_int32 tell0_frac;
+ int prefilter_tapset=0;
+ int pf_on;
+ int anti_collapse_rsv;
+ int anti_collapse_on=0;
+ int silence=0;
+ int tf_chan = 0;
+ opus_val16 tf_estimate;
+ int pitch_change=0;
+ opus_int32 tot_boost;
+ opus_val32 sample_max;
+ celt_glog maxDepth;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ const opus_int16 *eBands;
+ int secondMdct;
+ int signalBandwidth;
+ int transient_got_disabled=0;
+ celt_glog surround_masking=0;
+ celt_glog temporal_vbr=0;
+ celt_glog surround_trim = 0;
+ opus_int32 equiv_rate;
+ int hybrid;
+ int weak_transient = 0;
+ int enable_tf_analysis;
+ opus_val16 tone_freq=-1;
+ opus_val32 toneishness=0;
+ VARDECL(celt_glog, surround_dynalloc);
+ int qext_bytes=0;
+ int packet_size_cap = 1275;
+#ifdef ENABLE_QEXT
+ int qext_scale;
+ int qext_end=0;
+ int qext_intensity=0;
+ int qext_dual_stereo=0;
+ int padding_len_bytes=0;
+ unsigned char *ext_payload;
+ opus_int32 qext_bits;
+ ec_enc ext_enc;
+ VARDECL(int, extra_quant);
+ VARDECL(int, extra_pulses);
+ VARDECL(celt_glog, error_bak);
+ const CELTMode *qext_mode = NULL;
+ CELTMode qext_mode_struct;
+ celt_ener qext_bandE[2*NB_QEXT_BANDS];
+ celt_glog qext_bandLogE[2*NB_QEXT_BANDS];
+ celt_glog *qext_oldBandE=NULL;
+ celt_glog qext_error[2*NB_QEXT_BANDS];
+#endif
+ ALLOC_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+ start = st->start;
+ end = st->end;
+ hybrid = start != 0;
+ tf_estimate = 0;
+ if (nbCompressedBytes<2 || pcm==NULL)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ frame_size *= st->upsample;
+ for (LM=0;LM<=mode->maxLM;LM++)
+ if (mode->shortMdctSize<<LM==frame_size)
+ break;
+ if (LM>mode->maxLM)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ M=1<<LM;
+ N = M*mode->shortMdctSize;
+
+#ifdef ENABLE_QEXT
+ qext_scale = st->qext_scale;
+ if (st->enable_qext) packet_size_cap = QEXT_PACKET_SIZE_CAP;
+#endif
+
+ prefilter_mem = st->in_mem+CC*(overlap);
+ oldBandE = (celt_glog*)(st->in_mem+CC*(overlap+QEXT_SCALE(COMBFILTER_MAXPERIOD)));
+ oldLogE = oldBandE + CC*nbEBands;
+ oldLogE2 = oldLogE + CC*nbEBands;
+ energyError = oldLogE2 + CC*nbEBands;
+
+ if (enc==NULL)
+ {
+ tell0_frac=tell=1;
+ nbFilledBytes=0;
+ } else {
+ tell0_frac=ec_tell_frac(enc);
+ tell=ec_tell(enc);
+ nbFilledBytes=(tell+4)>>3;
+ }
+
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+ if (st->signalling && enc==NULL)
+ {
+ int tmp = (mode->effEBands-end)>>1;
+ end = st->end = IMAX(1, mode->effEBands-tmp);
+ compressed[0] = tmp<<5;
+ compressed[0] |= LM<<3;
+ compressed[0] |= (C==2)<<2;
+ /* Convert "standard mode" to Opus header */
+# ifndef ENABLE_QEXT
+ if (mode->Fs==48000 && mode->shortMdctSize==120)
+# endif
+ {
+ int c0 = toOpus(compressed[0]);
+ if (c0<0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ compressed[0] = c0;
+ }
+ compressed++;
+ nbCompressedBytes--;
+ }
+#else
+ celt_assert(st->signalling==0);
+#endif
+
+ /* Can't produce more than 1275 output bytes for the main payload, plus any QEXT extra data. */
+ nbCompressedBytes = IMIN(nbCompressedBytes,packet_size_cap);
+
+ if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX)
+ {
+ vbr_rate = bitrate_to_bits(st->bitrate, mode->Fs, frame_size)<<BITRES;
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+ if (st->signalling)
+ vbr_rate -= 8<<BITRES;
+#endif
+ effectiveBytes = vbr_rate>>(3+BITRES);
+ } else {
+ opus_int32 tmp;
+ vbr_rate = 0;
+ tmp = st->bitrate*frame_size;
+ if (tell>1)
+ tmp += tell*mode->Fs;
+ if (st->bitrate!=OPUS_BITRATE_MAX)
+ {
+ nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
+ (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling));
+ if (enc != NULL)
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+ effectiveBytes = nbCompressedBytes - nbFilledBytes;
+ }
+ nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
+ equiv_rate = ((opus_int32)nbCompressedBytes*8*50 << (3-LM)) - (40*C+20)*((400>>LM) - 50);
+ if (st->bitrate != OPUS_BITRATE_MAX)
+ equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50));
+
+ if (enc==NULL)
+ {
+ ec_enc_init(&_enc, compressed, nbCompressedBytes);
+ enc = &_enc;
+ }
+
+ if (vbr_rate>0)
+ {
+ /* Computes the max bit-rate allowed in VBR mode to avoid violating the
+ target rate and buffering.
+ We must do this up front so that bust-prevention logic triggers
+ correctly if we don't have enough bits. */
+ if (st->constrained_vbr)
+ {
+ opus_int32 vbr_bound;
+ opus_int32 max_allowed;
+ /* We could use any multiple of vbr_rate as bound (depending on the
+ delay).
+ This is clamped to ensure we use at least two bytes if the encoder
+ was entirely empty, but to allow 0 in hybrid mode. */
+ vbr_bound = vbr_rate;
+ max_allowed = IMIN(IMAX(tell==1?2:0,
+ (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)),
+ nbAvailableBytes);
+ if(max_allowed < nbAvailableBytes)
+ {
+ nbCompressedBytes = nbFilledBytes+max_allowed;
+ nbAvailableBytes = max_allowed;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+ }
+ }
+ total_bits = nbCompressedBytes*8;
+
+ effEnd = end;
+ if (effEnd > mode->effEBands)
+ effEnd = mode->effEBands;
+
+ ALLOC(in, CC*(N+overlap), celt_sig);
+
+ sample_max=MAX32(st->overlap_max, celt_maxabs_res(pcm, C*(N-overlap)/st->upsample));
+ st->overlap_max=celt_maxabs_res(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample);
+ sample_max=MAX32(sample_max, st->overlap_max);
+#ifdef FIXED_POINT
+ silence = (sample_max==0);
+#else
+ silence = (sample_max <= (opus_val16)1/(1<<st->lsb_depth));
+#endif
+#ifdef FUZZING
+ if ((rand()&0x3F)==0)
+ silence = 1;
+#endif
+ if (tell==1)
+ ec_enc_bit_logp(enc, silence, 15);
+ else
+ silence=0;
+ if (silence)
+ {
+ /*In VBR mode there is no need to send more than the minimum. */
+ if (vbr_rate>0)
+ {
+ effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2);
+ total_bits=nbCompressedBytes*8;
+ nbAvailableBytes=2;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+#ifdef ENABLE_QEXT
+ else if (st->enable_qext) {
+ nbCompressedBytes = IMIN(nbCompressedBytes, 1275);
+ nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
+ total_bits = nbCompressedBytes*8;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+#endif
+ /* Pretend we've filled all the remaining bits with zeros
+ (that's what the initialiser did anyway) */
+ tell = nbCompressedBytes*8;
+ enc->nbits_total+=tell-ec_tell(enc);
+ }
+ c=0; do {
+ int need_clip=0;
+#ifdef FIXED_POINT
+ need_clip = st->clip && sample_max>65536<<RES_SHIFT;
+#else
+ need_clip = st->clip && sample_max>65536.f;
+#endif
+ celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample,
+ mode->preemph, st->preemph_memE+c, need_clip);
+ OPUS_COPY(in+c*(N+overlap), &prefilter_mem[(1+c)*QEXT_SCALE(COMBFILTER_MAXPERIOD)-overlap], overlap);
+ } while (++c<CC);
+
+
+ tone_freq = tone_detect(in, CC, N+overlap, &toneishness, mode->Fs);
+ isTransient = 0;
+ 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, tone_freq, toneishness);
+ }
+ toneishness = MIN32(toneishness, QCONST32(1.f, 29)-SHL32(tf_estimate, 15));
+ /* Find pitch period and gain */
+ {
+ int enabled;
+ int qg;
+ enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && tell+16<=total_bits && !st->disable_pf;
+
+ prefilter_tapset = st->tapset_decision;
+ pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, st->complexity, tf_estimate, nbAvailableBytes, &st->analysis, tone_freq, toneishness ARG_QEXT(qext_scale));
+ if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3)
+ && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period))
+ pitch_change = 1;
+ if (pf_on==0)
+ {
+ if(!hybrid && tell+16<=total_bits)
+ ec_enc_bit_logp(enc, 0, 1);
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ int octave;
+ ec_enc_bit_logp(enc, 1, 1);
+ pitch_index += 1;
+ octave = EC_ILOG(pitch_index)-5;
+ ec_enc_uint(enc, octave, 6);
+ ec_enc_bits(enc, pitch_index-(16<<octave), 4+octave);
+ pitch_index -= 1;
+ ec_enc_bits(enc, qg, 3);
+ ec_enc_icdf(enc, prefilter_tapset, tapset_icdf, 2);
+ }
+ }
+ if (LM>0 && ec_tell(enc)+3<=total_bits)
+ {
+ if (isTransient)
+ shortBlocks = M;
+ } else {
+ isTransient = 0;
+ transient_got_disabled=1;
+ }
+
+ ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */
+ ALLOC(bandE,nbEBands*CC, celt_ener);
+ ALLOC(bandLogE,nbEBands*CC, celt_glog);
+
+ secondMdct = shortBlocks && st->complexity>=8;
+ ALLOC(bandLogE2, C*nbEBands, celt_glog);
+ if (secondMdct)
+ {
+ compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch);
+ compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch);
+ amp2Log2(mode, effEnd, end, bandE, bandLogE2, C);
+ for (c=0;c<C;c++)
+ {
+ for (i=0;i<end;i++)
+ bandLogE2[nbEBands*c+i] += HALF32(SHL32(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);
+
+ if (st->lfe)
+ {
+ for (i=2;i<end;i++)
+ {
+ bandE[i] = IMIN(bandE[i], MULT16_32_Q15(QCONST16(1e-4f,15),bandE[0]));
+ bandE[i] = MAX32(bandE[i], EPSILON);
+ }
+ }
+ amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+
+ ALLOC(surround_dynalloc, C*nbEBands, celt_glog);
+ OPUS_CLEAR(surround_dynalloc, end);
+ /* This computes how much masking takes place between surround channels */
+ if (!hybrid&&st->energy_mask&&!st->lfe)
+ {
+ int mask_end;
+ int midband;
+ int count_dynalloc;
+ opus_val32 mask_avg=0;
+ opus_val32 diff=0;
+ int count=0;
+ mask_end = IMAX(2,st->lastCodedBands);
+ for (c=0;c<C;c++)
+ {
+ for(i=0;i<mask_end;i++)
+ {
+ celt_glog mask;
+ opus_val16 mask16;
+ mask = MAXG(MING(st->energy_mask[nbEBands*c+i],
+ GCONST(.25f)), -GCONST(2.0f));
+ if (mask > 0)
+ mask = HALF32(mask);
+ mask16 = SHR32(mask, DB_SHIFT-10);
+ mask_avg += MULT16_16(mask16, eBands[i+1]-eBands[i]);
+ count += eBands[i+1]-eBands[i];
+ diff += MULT16_16(mask16, 1+2*i-mask_end);
+ }
+ }
+ celt_assert(count>0);
+ mask_avg = SHL32(DIV32_16(mask_avg,count), DB_SHIFT-10);
+ mask_avg += GCONST(.2f);
+ diff = SHL32(diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end), DB_SHIFT-10);
+ /* Again, being conservative */
+ diff = HALF32(diff);
+ diff = MAX32(MIN32(diff, GCONST(.031f)), -GCONST(.031f));
+ /* Find the band that's in the middle of the coded spectrum */
+ for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++);
+ count_dynalloc=0;
+ for(i=0;i<mask_end;i++)
+ {
+ opus_val32 lin;
+ celt_glog unmask;
+ lin = mask_avg + diff*(i-midband);
+ if (C==2)
+ unmask = MAXG(st->energy_mask[i], st->energy_mask[nbEBands+i]);
+ else
+ unmask = st->energy_mask[i];
+ unmask = MING(unmask, GCONST(.0f));
+ unmask -= lin;
+ if (unmask > GCONST(.25f))
+ {
+ surround_dynalloc[i] = unmask - GCONST(.25f);
+ count_dynalloc++;
+ }
+ }
+ if (count_dynalloc>=3)
+ {
+ /* If we need dynalloc in many bands, it's probably because our
+ initial masking rate was too low. */
+ mask_avg += GCONST(.25f);
+ if (mask_avg>0)
+ {
+ /* Something went really wrong in the original calculations,
+ disabling masking. */
+ mask_avg = 0;
+ diff = 0;
+ OPUS_CLEAR(surround_dynalloc, mask_end);
+ } else {
+ for(i=0;i<mask_end;i++)
+ surround_dynalloc[i] = MAXG(0, surround_dynalloc[i]-GCONST(.25f));
+ }
+ }
+ mask_avg += GCONST(.2f);
+ /* Convert to 1/64th units used for the trim */
+ surround_trim = 64*diff;
+ /*printf("%d %d ", mask_avg, surround_trim);*/
+ surround_masking = mask_avg;
+ }
+ /* Temporal VBR (but not for LFE) */
+ if (!st->lfe)
+ {
+ celt_glog follow=-QCONST32(10.0f, DB_SHIFT-5);
+ opus_val32 frame_avg=0;
+ celt_glog offset = shortBlocks?HALF32(SHL32(LM, DB_SHIFT-5)):0;
+ for(i=start;i<end;i++)
+ {
+ follow = MAXG(follow-QCONST32(1.0f, DB_SHIFT-5), SHR32(bandLogE[i],5)-offset);
+ if (C==2)
+ follow = MAXG(follow, SHR32(bandLogE[i+nbEBands],5)-offset);
+ frame_avg += follow;
+ }
+ frame_avg /= (end-start);
+ temporal_vbr = SUB32(SHL32(frame_avg, 5),st->spec_avg);
+ temporal_vbr = MING(GCONST(3.f), MAXG(-GCONST(1.5f), temporal_vbr));
+ st->spec_avg += MULT16_32_Q15(QCONST16(.02f, 15), temporal_vbr);
+ }
+ /*for (i=0;i<21;i++)
+ printf("%f ", bandLogE[i]);
+ printf("\n");*/
+
+ if (!secondMdct)
+ {
+ OPUS_COPY(bandLogE2, bandLogE, C*nbEBands);
+ }
+
+ /* Last chance to catch any transient we might have missed in the
+ time-domain analysis */
+ if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe && !hybrid)
+ {
+ if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C))
+ {
+ isTransient = 1;
+ shortBlocks = M;
+ compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
+ compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch);
+ amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
+ /* Compensate for the scaling of short vs long mdcts */
+ for (c=0;c<C;c++)
+ {
+ for (i=0;i<end;i++)
+ bandLogE2[nbEBands*c+i] += HALF32(SHL32(LM, DB_SHIFT));
+ }
+ tf_estimate = QCONST16(.2f,14);
+ }
+ }
+
+ if (LM>0 && ec_tell(enc)+3<=total_bits)
+ ec_enc_bit_logp(enc, isTransient, 3);
+
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+
+ /* Band normalisation */
+ normalise_bands(mode, freq, X, bandE, effEnd, C, M);
+
+ enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe && toneishness < QCONST32(.98f, 29);
+
+ ALLOC(offsets, nbEBands, int);
+ ALLOC(importance, nbEBands, int);
+ ALLOC(spread_weight, nbEBands, int);
+
+ maxDepth = dynalloc_analysis(bandLogE, bandLogE2, oldBandE, 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, tone_freq, toneishness ARG_QEXT(qext_scale));
+
+ ALLOC(tf_res, nbEBands, int);
+ /* Disable variable tf resolution for hybrid and at very low bitrate */
+ if (enable_tf_analysis)
+ {
+ int lambda;
+ lambda = IMAX(80, 20480/effectiveBytes + 2);
+ tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance);
+ for (i=effEnd;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 {
+ for (i=0;i<end;i++)
+ tf_res[i] = isTransient;
+ tf_select=0;
+ }
+
+ ALLOC(error, C*nbEBands, celt_glog);
+ 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])) < GCONST(2.f))
+ {
+ bandLogE[i+c*nbEBands] -= MULT16_32_Q15(QCONST16(0.25f, 15), energyError[i+c*nbEBands]);
+ }
+ }
+ } while (++c < C);
+ quant_coarse_energy(mode, start, end, effEnd, bandLogE,
+ oldBandE, total_bits, error, enc,
+ C, LM, nbAvailableBytes, st->force_intra,
+ &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe);
+
+ tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc);
+
+ if (ec_tell(enc)+4<=total_bits)
+ {
+ if (st->lfe)
+ {
+ st->tapset_decision = 0;
+ st->spread_decision = SPREAD_NORMAL;
+ } else if (hybrid)
+ {
+ if (st->complexity == 0)
+ st->spread_decision = SPREAD_NONE;
+ else if (isTransient)
+ st->spread_decision = SPREAD_NORMAL;
+ else
+ st->spread_decision = SPREAD_AGGRESSIVE;
+ } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C)
+ {
+ if (st->complexity == 0)
+ st->spread_decision = SPREAD_NONE;
+ else
+ st->spread_decision = SPREAD_NORMAL;
+ } else {
+ /* Disable new spreading+tapset estimator until we can show it works
+ better than the old one. So far it seems like spreading_decision()
+ works best. */
+#if 0
+ if (st->analysis.valid)
+ {
+ static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)};
+ static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)};
+ static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)};
+ static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)};
+ st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision);
+ st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision);
+ } else
+#endif
+ {
+ st->spread_decision = spreading_decision(mode, X,
+ &st->tonal_average, st->spread_decision, &st->hf_average,
+ &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M, spread_weight);
+ }
+ /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/
+ /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/
+ }
+ ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
+ } else {
+ st->spread_decision = SPREAD_NORMAL;
+ }
+
+ /* For LFE, everything interesting is in the first band */
+ if (st->lfe)
+ offsets[0] = IMIN(8, effectiveBytes/3);
+ ALLOC(cap, nbEBands, int);
+ init_caps(mode,cap,LM,C);
+
+ dynalloc_logp = 6;
+ total_bits<<=BITRES;
+ total_boost = 0;
+ tell = ec_tell_frac(enc);
+ for (i=start;i<end;i++)
+ {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ int j;
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ for (j = 0; tell+(dynalloc_loop_logp<<BITRES) < total_bits-total_boost
+ && boost < cap[i]; j++)
+ {
+ int flag;
+ flag = j<offsets[i];
+ ec_enc_bit_logp(enc, flag, dynalloc_loop_logp);
+ tell = ec_tell_frac(enc);
+ if (!flag)
+ break;
+ boost += quanta;
+ total_boost += quanta;
+ dynalloc_loop_logp = 1;
+ }
+ /* Making dynalloc more likely */
+ if (j)
+ dynalloc_logp = IMAX(2, dynalloc_logp-1);
+ offsets[i] = boost;
+ }
+
+ if (C==2)
+ {
+ static const opus_val16 intensity_thresholds[21]=
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 off*/
+ { 1, 2, 3, 4, 5, 6, 7, 8,16,24,36,44,50,56,62,67,72,79,88,106,134};
+ static const opus_val16 intensity_histeresis[21]=
+ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8};
+
+ /* Always use MS for 2.5 ms frames until we can do a better analysis */
+ if (LM!=0)
+ dual_stereo = stereo_analysis(mode, X, LM, N);
+
+ st->intensity = hysteresis_decision((opus_val16)(equiv_rate/1000),
+ intensity_thresholds, intensity_histeresis, 21, st->intensity);
+ st->intensity = IMIN(end,IMAX(start, st->intensity));
+ }
+
+ alloc_trim = 5;
+ if (tell+(6<<BITRES) <= total_bits - total_boost)
+ {
+ if (start > 0 || st->lfe)
+ {
+ st->stereo_saving = 0;
+ alloc_trim = 5;
+ } else {
+ alloc_trim = alloc_trim_analysis(mode, X, bandLogE,
+ end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate,
+ st->intensity, surround_trim, equiv_rate, st->arch);
+ }
+ ec_enc_icdf(enc, alloc_trim, trim_icdf, 7);
+ tell = ec_tell_frac(enc);
+ }
+
+ /* In VBR mode the frame size must not be reduced so much that it would
+ 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));
+ /* Variable bitrate */
+ if (vbr_rate>0)
+ {
+ opus_val16 alpha;
+ opus_int32 delta;
+ /* The target rate in 8th bits per frame */
+ opus_int32 target, base_target;
+ int lm_diff = mode->maxLM - LM;
+
+ /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
+ The CELT allocator will just not be able to use more than that anyway. */
+ nbCompressedBytes = IMIN(nbCompressedBytes,packet_size_cap>>(3-LM));
+ if (!hybrid)
+ {
+ base_target = vbr_rate - ((40*C+20)<<BITRES);
+ } else {
+ base_target = IMAX(0, vbr_rate - ((9*C+4)<<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,
+ st->lastCodedBands, C, st->intensity, st->constrained_vbr,
+ st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
+ st->lfe, st->energy_mask!=NULL, surround_masking,
+ temporal_vbr ARG_QEXT(st->enable_qext));
+ } 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;
+
+ nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3);
+ nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes);
+ nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes);
+
+ /* By how much did we "miss" the target on that frame */
+ delta = target - vbr_rate;
+
+ target=nbAvailableBytes<<(BITRES+3);
+
+ /*If the frame is silent we don't adjust our drift, otherwise
+ the encoder will shoot to very high rates after hitting a
+ span of silence, but we do allow the bitres to refill.
+ This means that we'll undershoot our target in CVBR/VBR modes
+ on files with lots of silence. */
+ if(silence)
+ {
+ nbAvailableBytes = 2;
+ target = 2*8<<BITRES;
+ delta = 0;
+ }
+
+ if (st->vbr_count < 970)
+ {
+ st->vbr_count++;
+ alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16));
+ } else
+ alpha = QCONST16(.001f,15);
+ /* How many bits have we used in excess of what we're allowed */
+ if (st->constrained_vbr)
+ st->vbr_reservoir += target - vbr_rate;
+ /*printf ("%d\n", st->vbr_reservoir);*/
+
+ /* Compute the offset we need to apply in order to reach the target */
+ if (st->constrained_vbr)
+ {
+ st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<<lm_diff))-st->vbr_offset-st->vbr_drift);
+ st->vbr_offset = -st->vbr_drift;
+ }
+ /*printf ("%d\n", st->vbr_drift);*/
+
+ if (st->constrained_vbr && st->vbr_reservoir < 0)
+ {
+ /* We're under the min value -- increase rate */
+ int adjust = (-st->vbr_reservoir)/(8<<BITRES);
+ /* Unless we're just coding silence */
+ nbAvailableBytes += silence?0:adjust;
+ st->vbr_reservoir = 0;
+ /*printf ("+%d\n", adjust);*/
+ }
+ nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes);
+ /*printf("%d\n", nbCompressedBytes*50*8);*/
+ /* This moves the raw bits to take into account the new compressed size */
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+#ifdef ENABLE_QEXT
+ if (st->enable_qext) {
+ int new_compressedBytes;
+ /* Don't give any bits for the first 80 kb/s per channel. Then 80% of the excess. */
+ opus_int32 offset = bitrate_to_bits(C*80000, mode->Fs, frame_size)/8;
+ qext_bytes = IMAX(nbCompressedBytes-1275, IMAX(0, (nbCompressedBytes-offset)*4/5));
+ if (qext_bytes > 20) {
+ opus_int32 target;
+ opus_val16 scale;
+ target = ((nbCompressedBytes-qext_bytes/3)*8<<BITRES);
+ if (!vbr_rate) {
+ opus_val16 tf_estimate2;
+ target -= ((40*C+20)<<BITRES);
+ tf_estimate2 = MIN32(QCONST16(1.f, 14), 2*EXTEND32(tf_estimate));
+ target = compute_vbr(mode, &st->analysis, target, LM, equiv_rate,
+ st->lastCodedBands, C, st->intensity, st->constrained_vbr,
+ st->stereo_saving, tot_boost, tf_estimate2, pitch_change, maxDepth,
+ st->lfe, st->energy_mask!=NULL, surround_masking,
+ temporal_vbr ARG_QEXT(st->enable_qext));
+ target += tell;
+ }
+ scale = PSHR32(toneishness,14);
+ scale = Q15ONE - MULT16_16_Q15(scale, scale);
+ qext_bytes += MULT16_32_Q15(scale, (nbCompressedBytes-(target/(8<<BITRES))) - qext_bytes);
+ qext_bytes = IMAX(nbCompressedBytes-1275, IMAX(21, qext_bytes));
+ }
+ padding_len_bytes = (qext_bytes+253)/254;
+ qext_bytes = IMIN(qext_bytes, nbCompressedBytes-min_allowed-padding_len_bytes-1);
+ padding_len_bytes = (qext_bytes+253)/254;
+ if (qext_bytes > 20) {
+ new_compressedBytes = nbCompressedBytes-qext_bytes-padding_len_bytes-1;
+ ec_enc_shrink(enc, new_compressedBytes);
+ if (compressed == NULL) {
+ compressed = enc->buf;
+ }
+ compressed[-1] |= 0x03; /* Code 3 packet */
+ enc->buf += 1+padding_len_bytes;
+ OPUS_MOVE(compressed+1+padding_len_bytes, compressed, new_compressedBytes);
+ compressed[0] = 0x41; /* Set padding */
+ for (i=0;i<padding_len_bytes-1;i++) compressed[i+1] = 255;
+ compressed[padding_len_bytes] = qext_bytes%254 == 0 ? 254 : qext_bytes%254;
+ ext_payload = compressed+padding_len_bytes+1+new_compressedBytes;
+ ext_payload[0] = QEXT_EXTENSION_ID<<1;
+ ext_payload += 1;
+ qext_bytes -= 1;
+ OPUS_CLEAR(ext_payload, qext_bytes);
+ ec_enc_init(&ext_enc, ext_payload, qext_bytes);
+ nbCompressedBytes = new_compressedBytes;
+ if (end == nbEBands && (mode->Fs == 48000 || mode->Fs == 96000) && (mode->shortMdctSize==120*qext_scale || mode->shortMdctSize==90*qext_scale)) {
+ compute_qext_mode(&qext_mode_struct, mode);
+ qext_mode = &qext_mode_struct;
+ qext_end = (qext_scale == 2) ? NB_QEXT_BANDS : 2;
+ ec_enc_bit_logp(&ext_enc, qext_end == NB_QEXT_BANDS, 1);
+ }
+ } else {
+ ec_enc_init(&ext_enc, NULL, 0);
+ qext_bytes = 0;
+ }
+ } else {
+ ec_enc_init(&ext_enc, NULL, 0);
+ }
+#endif
+
+ /* Bit allocation */
+ ALLOC(fine_quant, nbEBands, int);
+ ALLOC(pulses, nbEBands, int);
+ ALLOC(fine_priority, nbEBands, int);
+
+ /* bits = packet size - where we are - safety*/
+ bits = (((opus_int32)nbCompressedBytes*8)<<BITRES) - (opus_int32)ec_tell_frac(enc) - 1;
+ anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+ bits -= anti_collapse_rsv;
+ signalBandwidth = end-1;
+#ifndef DISABLE_FLOAT_API
+ if (st->analysis.valid)
+ {
+ int min_bandwidth;
+ if (equiv_rate < (opus_int32)32000*C)
+ min_bandwidth = 13;
+ else if (equiv_rate < (opus_int32)48000*C)
+ min_bandwidth = 16;
+ else if (equiv_rate < (opus_int32)60000*C)
+ min_bandwidth = 18;
+ else if (equiv_rate < (opus_int32)80000*C)
+ min_bandwidth = 19;
+ else
+ min_bandwidth = 20;
+ signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth);
+ }
+#endif
+ if (st->lfe)
+ signalBandwidth = 1;
+ codedBands = clt_compute_allocation(mode, start, end, offsets, cap,
+ alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses,
+ fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth);
+ if (st->lastCodedBands)
+ st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands));
+ else
+ st->lastCodedBands = codedBands;
+
+ quant_fine_energy(mode, start, end, oldBandE, error, NULL, fine_quant, enc, C);
+ OPUS_CLEAR(energyError, nbEBands*CC);
+#ifdef ENABLE_QEXT
+ if (qext_mode)
+ {
+ /* Don't bias for intra. */
+ opus_val32 qext_delayedIntra=0;
+ qext_oldBandE = energyError + CC*nbEBands;
+ compute_band_energies(qext_mode, freq, qext_bandE, qext_end, C, LM, st->arch);
+ normalise_bands(qext_mode, freq, X, qext_bandE, qext_end, C, M);
+ amp2Log2(qext_mode, qext_end, qext_end, qext_bandE, qext_bandLogE, C);
+ if (C==2) {
+ qext_intensity = qext_end;
+ qext_dual_stereo = dual_stereo;
+ encode_qext_stereo_params(&ext_enc, qext_end, qext_intensity, qext_dual_stereo);
+ }
+ quant_coarse_energy(qext_mode, 0, qext_end, qext_end, qext_bandLogE,
+ qext_oldBandE, qext_bytes*8, qext_error, &ext_enc,
+ C, LM, qext_bytes, st->force_intra,
+ &qext_delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe);
+ }
+ ALLOC(extra_quant, nbEBands+NB_QEXT_BANDS, int);
+ ALLOC(extra_pulses, nbEBands+NB_QEXT_BANDS, int);
+ ALLOC(error_bak, C*nbEBands, celt_glog);
+
+ qext_bits = ((opus_int32)qext_bytes*8<<BITRES) - (opus_int32)ec_tell_frac(enc) - 1;
+ clt_compute_extra_allocation(mode, qext_mode, start, end, qext_end, bandLogE, qext_bandLogE,
+ qext_bits, extra_pulses, extra_quant, C, LM, &ext_enc, 1, tone_freq, toneishness);
+ OPUS_COPY(error_bak, error, C*nbEBands);
+ if (qext_bytes > 0) {
+ quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, extra_quant, &ext_enc, C);
+ }
+#endif
+
+ /* Residual quantisation */
+ ALLOC(collapse_masks, C*nbEBands, unsigned char);
+ quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
+ bandE, pulses, shortBlocks, st->spread_decision,
+ dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv,
+ balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch, st->disable_inv
+ ARG_QEXT(&ext_enc) ARG_QEXT(extra_pulses)
+ ARG_QEXT(qext_bytes*(8<<BITRES)) ARG_QEXT(cap));
+
+#ifdef ENABLE_QEXT
+ if (qext_mode) {
+ VARDECL(int, zeros);
+ VARDECL(unsigned char, qext_collapse_masks);
+ ec_enc dummy_enc;
+ int ext_balance;
+ ALLOC(zeros, nbEBands, int);
+ ALLOC(qext_collapse_masks, C*NB_QEXT_BANDS, unsigned char);
+ ec_enc_init(&dummy_enc, NULL, 0);
+ OPUS_CLEAR(zeros, end);
+ ext_balance = qext_bytes*(8<<BITRES) - ec_tell_frac(&ext_enc);
+ for (i=0;i<qext_end;i++) ext_balance -= extra_pulses[nbEBands+i] + C*(extra_quant[nbEBands+1]<<BITRES);
+ quant_fine_energy(qext_mode, 0, qext_end, qext_oldBandE, qext_error, NULL, &extra_quant[nbEBands], &ext_enc, C);
+ quant_all_bands(1, qext_mode, 0, qext_end, X, C==2 ? X+N : NULL, qext_collapse_masks,
+ qext_bandE, &extra_pulses[nbEBands], shortBlocks, st->spread_decision,
+ qext_dual_stereo, qext_intensity, zeros, qext_bytes*(8<<BITRES),
+ ext_balance, &ext_enc, LM, qext_end, &st->rng, st->complexity, st->arch, st->disable_inv, &dummy_enc, zeros, 0, NULL);
+ }
+#endif
+
+ if (anti_collapse_rsv > 0)
+ {
+ anti_collapse_on = st->consec_transient<2;
+#ifdef FUZZING
+ anti_collapse_on = rand()&0x1;
+#endif
+ ec_enc_bits(enc, anti_collapse_on, 1);
+ }
+ if (qext_bytes == 0)
+ quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
+ c=0;
+ do {
+ for (i=start;i<end;i++)
+ {
+ energyError[i+c*nbEBands] = MAXG(-GCONST(0.5f), MING(GCONST(0.5f), error[i+c*nbEBands]));
+ }
+ } while (++c < C);
+#ifdef ENABLE_QEXT
+ if (qext_bytes > 0)
+ quant_energy_finalise(mode, start, end, NULL, error_bak, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
+#endif
+ if (silence)
+ {
+ for (i=0;i<C*nbEBands;i++)
+ oldBandE[i] = -GCONST(28.f);
+ }
+
+#ifdef RESYNTH
+ /* Re-synthesis of the coded audio if required */
+ {
+ celt_sig *out_mem[2];
+
+ if (anti_collapse_on)
+ {
+ anti_collapse(mode, X, collapse_masks, LM, C, N,
+ start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, 1, st->arch);
+ }
+
+ c=0; do {
+ OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, QEXT_SCALE(DEC_PITCH_BUF_SIZE)-N+overlap/2);
+ } while (++c<CC);
+
+ c=0; do {
+ out_mem[c] = st->syn_mem[c]+QEXT_SCALE(DEC_PITCH_BUF_SIZE)-N;
+ } while (++c<CC);
+
+ celt_synthesis(mode, X, out_mem, oldBandE, start, effEnd,
+ C, CC, isTransient, LM, st->upsample, silence, st->arch ARG_QEXT(qext_mode) ARG_QEXT(qext_oldBandE) ARG_QEXT(qext_end));
+
+ c=0; do {
+ st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+ st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD);
+ comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize,
+ st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset,
+ mode->window, overlap, st->arch);
+ if (LM!=0)
+ comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize,
+ st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset,
+ mode->window, overlap, st->arch);
+ } while (++c<CC);
+
+ /* We reuse freq[] as scratch space for the de-emphasis */
+ deemphasis(out_mem, (opus_res*)pcm, N, CC, st->upsample, mode->preemph, st->preemph_memD, 0);
+ st->prefilter_period_old = st->prefilter_period;
+ st->prefilter_gain_old = st->prefilter_gain;
+ st->prefilter_tapset_old = st->prefilter_tapset;
+ }
+#endif
+
+ st->prefilter_period = pitch_index;
+ st->prefilter_gain = gain1;
+ st->prefilter_tapset = prefilter_tapset;
+#ifdef RESYNTH
+ if (LM!=0)
+ {
+ st->prefilter_period_old = st->prefilter_period;
+ st->prefilter_gain_old = st->prefilter_gain;
+ st->prefilter_tapset_old = st->prefilter_tapset;
+ }
+#endif
+
+ if (CC==2&&C==1) {
+ OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands);
+ }
+
+ if (!isTransient)
+ {
+ OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands);
+ OPUS_COPY(oldLogE, oldBandE, CC*nbEBands);
+ } else {
+ for (i=0;i<CC*nbEBands;i++)
+ oldLogE[i] = MING(oldLogE[i], oldBandE[i]);
+ }
+ /* In case start or end were to change */
+ c=0; do
+ {
+ for (i=0;i<start;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-GCONST(28.f);
+ }
+ for (i=end;i<nbEBands;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-GCONST(28.f);
+ }
+ } while (++c<CC);
+
+ if (isTransient || transient_got_disabled)
+ st->consec_transient++;
+ else
+ st->consec_transient=0;
+ st->rng = enc->rng;
+
+ /* If there's any room left (can only happen for very high rates),
+ it's already filled with zeros */
+ ec_enc_done(enc);
+#ifdef ENABLE_QEXT
+ ec_enc_done(&ext_enc);
+ if (qext_bytes > 0)
+ nbCompressedBytes += padding_len_bytes+2+qext_bytes;
+ if (qext_bytes) st->rng = st->rng ^ ext_enc.rng;
+ if (ec_get_error(&ext_enc))
+ return OPUS_INTERNAL_ERROR;
+#endif
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+ if (st->signalling)
+ nbCompressedBytes++;
+#endif
+
+ RESTORE_STACK;
+ if (ec_get_error(enc))
+ return OPUS_INTERNAL_ERROR;
+ else
+ return nbCompressedBytes;
+}
+
+
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+
+#if defined(FIXED_POINT) && !defined(ENABLE_RES24)
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+#else
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(opus_res, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(in, C*N, opus_res);
+
+ for (j=0;j<C*N;j++)
+ in[j] = INT16TORES(pcm[j]);
+
+ ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((opus_int16*)pcm)[j]=RES2INT16(in[j]);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+
+#if defined(FIXED_POINT) && defined(ENABLE_RES24)
+int opus_custom_encode24(CELTEncoder * OPUS_RESTRICT st, const opus_int32 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+#else
+int opus_custom_encode24(CELTEncoder * OPUS_RESTRICT st, const opus_int32 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(opus_res, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(in, C*N, opus_res);
+
+ for (j=0;j<C*N;j++)
+ in[j] = INT24TORES(pcm[j]);
+
+ ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((opus_int32*)pcm)[j]=RES2INT24(in[j]);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+
+#ifndef DISABLE_FLOAT_API
+
+# if !defined(FIXED_POINT)
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+# else
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(opus_res, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(in, C*N, opus_res);
+
+ for (j=0;j<C*N;j++)
+ in[j] = FLOAT2RES(pcm[j]);
+
+ ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((float*)pcm)[j]=RES2FLOAT(in[j]);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+# endif
+
+#endif
+
+#endif /* CUSTOM_MODES */
+
+int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
+{
+ va_list ap;
+
+ va_start(ap, request);
+ switch (request)
+ {
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>10)
+ goto bad_arg;
+ st->complexity = value;
+ }
+ break;
+ case CELT_SET_START_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 || value>=st->mode->nbEBands)
+ goto bad_arg;
+ st->start = value;
+ }
+ break;
+ case CELT_SET_END_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>st->mode->nbEBands)
+ goto bad_arg;
+ st->end = value;
+ }
+ break;
+ case CELT_SET_PREDICTION_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>2)
+ goto bad_arg;
+ st->disable_pf = value<=1;
+ st->force_intra = value==0;
+ }
+ break;
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>100)
+ goto bad_arg;
+ st->loss_rate = value;
+ }
+ break;
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->constrained_vbr = value;
+ }
+ break;
+ case OPUS_SET_VBR_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->vbr = value;
+ }
+ break;
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<=500 && value!=OPUS_BITRATE_MAX)
+ goto bad_arg;
+ value = IMIN(value, 750000*st->channels);
+ st->bitrate = value;
+ }
+ break;
+ case CELT_SET_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>2)
+ goto bad_arg;
+ st->stream_channels = value;
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<8 || value>24)
+ goto bad_arg;
+ st->lsb_depth=value;
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ *value=st->lsb_depth;
+ }
+ break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->disable_inv = value;
+ }
+ break;
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->disable_inv;
+ }
+ break;
+#ifdef ENABLE_QEXT
+ case OPUS_SET_QEXT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->enable_qext = value;
+ }
+ break;
+ case OPUS_GET_QEXT_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->enable_qext;
+ }
+ break;
+#endif
+ case OPUS_RESET_STATE:
+ {
+ int i;
+ celt_glog *oldBandE, *oldLogE, *oldLogE2;
+ oldBandE = (celt_glog*)(st->in_mem+st->channels*(st->mode->overlap+QEXT_SCALE2(COMBFILTER_MAXPERIOD, st->qext_scale)));
+ oldLogE = oldBandE + st->channels*st->mode->nbEBands;
+ oldLogE2 = oldLogE + st->channels*st->mode->nbEBands;
+ OPUS_CLEAR((char*)&st->ENCODER_RESET_START,
+ opus_custom_encoder_get_size(st->mode, st->channels)-
+ ((char*)&st->ENCODER_RESET_START - (char*)st));
+ for (i=0;i<st->channels*st->mode->nbEBands;i++)
+ oldLogE[i]=oldLogE2[i]=-GCONST(28.f);
+ st->vbr_offset = 0;
+ st->delayedIntra = 1;
+ st->spread_decision = SPREAD_NORMAL;
+ st->tonal_average = 256;
+ st->hf_average = 0;
+ st->tapset_decision = 0;
+ }
+ break;
+#if defined(CUSTOM_MODES) || defined(ENABLE_OPUS_CUSTOM_API)
+ case CELT_SET_INPUT_CLIPPING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->clip = value;
+ }
+ break;
+#endif
+ case CELT_SET_SIGNALLING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->signalling = value;
+ }
+ break;
+ case CELT_SET_ANALYSIS_REQUEST:
+ {
+ AnalysisInfo *info = va_arg(ap, AnalysisInfo *);
+ if (info)
+ OPUS_COPY(&st->analysis, info, 1);
+ }
+ break;
+ case CELT_SET_SILK_INFO_REQUEST:
+ {
+ SILKInfo *info = va_arg(ap, SILKInfo *);
+ if (info)
+ OPUS_COPY(&st->silk_info, info, 1);
+ }
+ break;
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (value==0)
+ goto bad_arg;
+ *value=st->mode;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 * value = va_arg(ap, opus_uint32 *);
+ if (value==0)
+ goto bad_arg;
+ *value=st->rng;
+ }
+ break;
+ case OPUS_SET_LFE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->lfe = value;
+ }
+ break;
+ case OPUS_SET_ENERGY_MASK_REQUEST:
+ {
+ celt_glog *value = va_arg(ap, celt_glog*);
+ st->energy_mask = value;
+ }
+ break;
+ default:
+ goto bad_request;
+ }
+ va_end(ap);
+ return OPUS_OK;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+bad_request:
+ va_end(ap);
+ return OPUS_UNIMPLEMENTED;
+}
--- /dev/null
+# PowerShell script to copy encoder source files in addition to decoder files\r
+# This script should be run after copy_sources.sh to add encoder support\r
+\r
+$ErrorActionPreference = "Stop"\r
+\r
+$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path\r
+$ProjectRoot = Split-Path -Parent $ScriptDir\r
+\r
+Write-Host "=========================================="\r
+Write-Host "Copying Opus Encoder Source Files"\r
+Write-Host "=========================================="\r
+Write-Host "Project root: $ProjectRoot"\r
+Write-Host "Target directory: $ScriptDir"\r
+Write-Host ""\r
+\r
+# Create directories if they don't exist\r
+$dirs = @(\r
+ "$ScriptDir\src_lib",\r
+ "$ScriptDir\celt",\r
+ "$ScriptDir\silk",\r
+ "$ScriptDir\silk\fixed"\r
+)\r
+\r
+foreach ($dir in $dirs) {\r
+ if (-not (Test-Path $dir)) {\r
+ New-Item -ItemType Directory -Path $dir -Force | Out-Null\r
+ }\r
+}\r
+\r
+Write-Host "Created directory structure"\r
+Write-Host ""\r
+\r
+# Copy Opus API layer encoder sources\r
+Write-Host "Copying Opus encoder API sources..."\r
+$OpusEncoderFiles = @(\r
+ "src\opus_encoder.c",\r
+ "src\opus_multistream_encoder.c",\r
+ "src\opus_projection_encoder.c",\r
+ "src\analysis.c",\r
+ "src\mlp.c",\r
+ "src\mlp_data.c"\r
+)\r
+\r
+foreach ($file in $OpusEncoderFiles) {\r
+ $srcPath = Join-Path $ProjectRoot $file\r
+ $dstPath = Join-Path $ScriptDir "src_lib" (Split-Path -Leaf $file)\r
+ if (Test-Path $srcPath) {\r
+ Copy-Item $srcPath $dstPath -Force\r
+ Write-Host " Copied: $file"\r
+ } else {\r
+ Write-Host " Warning: $file not found"\r
+ }\r
+}\r
+\r
+Write-Host ""\r
+\r
+# Copy CELT encoder sources\r
+Write-Host "Copying CELT encoder sources..."\r
+$CeltEncoderFiles = @(\r
+ "celt\celt_encoder.c"\r
+)\r
+\r
+foreach ($file in $CeltEncoderFiles) {\r
+ $srcPath = Join-Path $ProjectRoot $file\r
+ $dstPath = Join-Path $ScriptDir "celt" (Split-Path -Leaf $file)\r
+ if (Test-Path $srcPath) {\r
+ Copy-Item $srcPath $dstPath -Force\r
+ Write-Host " Copied: $file"\r
+ } else {\r
+ Write-Host " Warning: $file not found"\r
+ }\r
+}\r
+\r
+Write-Host ""\r
+\r
+# Copy SILK encoder core sources\r
+Write-Host "Copying SILK encoder core sources..."\r
+$SilkEncoderCoreFiles = @(\r
+ "silk\enc_API.c",\r
+ "silk\init_encoder.c",\r
+ "silk\encode_indices.c",\r
+ "silk\encode_pulses.c",\r
+ "silk\NLSF_encode.c",\r
+ "silk\NLSF_VQ.c",\r
+ "silk\NLSF_del_dec_quant.c",\r
+ "silk\process_NLSFs.c"\r
+)\r
+\r
+foreach ($file in $SilkEncoderCoreFiles) {\r
+ $srcPath = Join-Path $ProjectRoot $file\r
+ $dstPath = Join-Path $ScriptDir "silk" (Split-Path -Leaf $file)\r
+ if (Test-Path $srcPath) {\r
+ Copy-Item $srcPath $dstPath -Force\r
+ Write-Host " Copied: $file"\r
+ } else {\r
+ Write-Host " Warning: $file not found"\r
+ }\r
+}\r
+\r
+# Copy SILK encoder stereo processing\r
+Write-Host "Copying SILK encoder stereo processing..."\r
+$SilkEncoderStereoFiles = @(\r
+ "silk\stereo_LR_to_MS.c",\r
+ "silk\stereo_encode_pred.c",\r
+ "silk\stereo_quant_pred.c"\r
+)\r
+\r
+foreach ($file in $SilkEncoderStereoFiles) {\r
+ $srcPath = Join-Path $ProjectRoot $file\r
+ $dstPath = Join-Path $ScriptDir "silk" (Split-Path -Leaf $file)\r
+ if (Test-Path $srcPath) {\r
+ Copy-Item $srcPath $dstPath -Force\r
+ Write-Host " Copied: $file"\r
+ } else {\r
+ Write-Host " Warning: $file not found"\r
+ }\r
+}\r
+\r
+# Copy SILK encoder NSQ (Noise Shaping Quantization)\r
+Write-Host "Copying SILK encoder NSQ sources..."\r
+$SilkEncoderNsqFiles = @(\r
+ "silk\NSQ.c",\r
+ "silk\NSQ_del_dec.c"\r
+)\r
+\r
+foreach ($file in $SilkEncoderNsqFiles) {\r
+ $srcPath = Join-Path $ProjectRoot $file\r
+ $dstPath = Join-Path $ScriptDir "silk" (Split-Path -Leaf $file)\r
+ if (Test-Path $srcPath) {\r
+ Copy-Item $srcPath $dstPath -Force\r
+ Write-Host " Copied: $file"\r
+ } else {\r
+ Write-Host " Warning: $file not found"\r
+ }\r
+}\r
+\r
+# Copy SILK encoder control and analysis\r
+Write-Host "Copying SILK encoder control and analysis..."\r
+$SilkEncoderControlFiles = @(\r
+ "silk\quant_LTP_gains.c",\r
+ "silk\VQ_WMat_EC.c",\r
+ "silk\VAD.c",\r
+ "silk\control_audio_bandwidth.c",\r
+ "silk\control_SNR.c",\r
+ "silk\control_codec.c",\r
+ "silk\check_control_input.c",\r
+ "silk\ana_filt_bank_1.c"\r
+)\r
+\r
+foreach ($file in $SilkEncoderControlFiles) {\r
+ $srcPath = Join-Path $ProjectRoot $file\r
+ $dstPath = Join-Path $ScriptDir "silk" (Split-Path -Leaf $file)\r
+ if (Test-Path $srcPath) {\r
+ Copy-Item $srcPath $dstPath -Force\r
+ Write-Host " Copied: $file"\r
+ } else {\r
+ Write-Host " Warning: $file not found"\r
+ }\r
+}\r
+\r
+# Copy SILK fixed-point encoder implementation\r
+Write-Host "Copying SILK fixed-point encoder implementation..."\r
+$fixedDir = Join-Path $ProjectRoot "silk\fixed"\r
+$targetFixedDir = Join-Path $ScriptDir "silk\fixed"\r
+if (Test-Path $fixedDir) {\r
+ $fixedFiles = Get-ChildItem -Path $fixedDir -Filter "*.c" -File\r
+ foreach ($file in $fixedFiles) {\r
+ Copy-Item $file.FullName $targetFixedDir -Force\r
+ }\r
+ $fixedHeaders = Get-ChildItem -Path $fixedDir -Filter "*.h" -File\r
+ foreach ($file in $fixedHeaders) {\r
+ Copy-Item $file.FullName $targetFixedDir -Force\r
+ }\r
+ Write-Host " Copied SILK fixed-point encoder sources and headers"\r
+}\r
+\r
+# Copy SILK float encoder implementation\r
+Write-Host "Copying SILK float encoder implementation..."\r
+$encodeFrameFlp = Join-Path $ProjectRoot "silk\float\encode_frame_FLP.c"\r
+$targetFlp = Join-Path $ScriptDir "silk\float\encode_frame_FLP.c"\r
+if (Test-Path $encodeFrameFlp) {\r
+ Copy-Item $encodeFrameFlp $targetFlp -Force\r
+ Write-Host " Copied: silk\float\encode_frame_FLP.c"\r
+}\r
+\r
+Write-Host ""\r
+Write-Host "=========================================="\r
+Write-Host "Encoder source files copied successfully!"\r
+Write-Host "=========================================="\r
+Write-Host ""\r
+Write-Host "Next steps:"\r
+Write-Host " 1. Review copied files"\r
+Write-Host " 2. Run: make -f Makefile.libopus"\r
+Write-Host " 3. This will create libopus_min.a with encoder support"\r
+Write-Host ""\r
--- /dev/null
+#!/bin/bash
+# Script to copy encoder source files in addition to decoder files
+# This script should be run after copy_sources.sh to add encoder support
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
+
+echo "=========================================="
+echo "Copying Opus Encoder Source Files"
+echo "=========================================="
+echo "Project root: $PROJECT_ROOT"
+echo "Target directory: $SCRIPT_DIR"
+echo ""
+
+# Create directories if they don't exist
+mkdir -p "$SCRIPT_DIR/src_lib"
+mkdir -p "$SCRIPT_DIR/celt"
+mkdir -p "$SCRIPT_DIR/silk"
+mkdir -p "$SCRIPT_DIR/silk/fixed"
+
+echo "Created directory structure"
+echo ""
+
+# Copy Opus API layer encoder sources
+echo "Copying Opus encoder API sources..."
+OPUS_ENCODER_FILES=(
+ "src/opus_encoder.c"
+ "src/opus_multistream_encoder.c"
+ "src/opus_projection_encoder.c"
+ "src/analysis.c"
+ "src/mlp.c"
+ "src/mlp_data.c"
+)
+
+for file in "${OPUS_ENCODER_FILES[@]}"; do
+ if [ -f "$PROJECT_ROOT/$file" ]; then
+ cp "$PROJECT_ROOT/$file" "$SCRIPT_DIR/src_lib/"
+ echo " Copied: $file"
+ else
+ echo " Warning: $file not found"
+ fi
+done
+
+echo ""
+
+# Copy CELT encoder sources
+echo "Copying CELT encoder sources..."
+CELT_ENCODER_FILES=(
+ "celt/celt_encoder.c"
+)
+
+for file in "${CELT_ENCODER_FILES[@]}"; do
+ if [ -f "$PROJECT_ROOT/$file" ]; then
+ cp "$PROJECT_ROOT/$file" "$SCRIPT_DIR/celt/"
+ echo " Copied: $file"
+ else
+ echo " Warning: $file not found"
+ fi
+done
+
+echo ""
+
+# Copy SILK encoder core sources
+echo "Copying SILK encoder core sources..."
+SILK_ENCODER_CORE_FILES=(
+ "silk/enc_API.c"
+ "silk/init_encoder.c"
+ "silk/encode_indices.c"
+ "silk/encode_pulses.c"
+ "silk/NLSF_encode.c"
+ "silk/NLSF_VQ.c"
+ "silk/NLSF_del_dec_quant.c"
+ "silk/process_NLSFs.c"
+)
+
+for file in "${SILK_ENCODER_CORE_FILES[@]}"; do
+ if [ -f "$PROJECT_ROOT/$file" ]; then
+ cp "$PROJECT_ROOT/$file" "$SCRIPT_DIR/silk/"
+ echo " Copied: $file"
+ else
+ echo " Warning: $file not found"
+ fi
+done
+
+# Copy SILK encoder stereo processing
+echo "Copying SILK encoder stereo processing..."
+SILK_ENCODER_STEREO_FILES=(
+ "silk/stereo_LR_to_MS.c"
+ "silk/stereo_encode_pred.c"
+ "silk/stereo_quant_pred.c"
+)
+
+for file in "${SILK_ENCODER_STEREO_FILES[@]}"; do
+ if [ -f "$PROJECT_ROOT/$file" ]; then
+ cp "$PROJECT_ROOT/$file" "$SCRIPT_DIR/silk/"
+ echo " Copied: $file"
+ else
+ echo " Warning: $file not found"
+ fi
+done
+
+# Copy SILK encoder NSQ (Noise Shaping Quantization)
+echo "Copying SILK encoder NSQ sources..."
+SILK_ENCODER_NSQ_FILES=(
+ "silk/NSQ.c"
+ "silk/NSQ_del_dec.c"
+)
+
+for file in "${SILK_ENCODER_NSQ_FILES[@]}"; do
+ if [ -f "$PROJECT_ROOT/$file" ]; then
+ cp "$PROJECT_ROOT/$file" "$SCRIPT_DIR/silk/"
+ echo " Copied: $file"
+ else
+ echo " Warning: $file not found"
+ fi
+done
+
+# Copy SILK encoder control and analysis
+echo "Copying SILK encoder control and analysis..."
+SILK_ENCODER_CONTROL_FILES=(
+ "silk/quant_LTP_gains.c"
+ "silk/VQ_WMat_EC.c"
+ "silk/VAD.c"
+ "silk/control_audio_bandwidth.c"
+ "silk/control_SNR.c"
+ "silk/control_codec.c"
+ "silk/check_control_input.c"
+ "silk/ana_filt_bank_1.c"
+)
+
+for file in "${SILK_ENCODER_CONTROL_FILES[@]}"; do
+ if [ -f "$PROJECT_ROOT/$file" ]; then
+ cp "$PROJECT_ROOT/$file" "$SCRIPT_DIR/silk/"
+ echo " Copied: $file"
+ else
+ echo " Warning: $file not found"
+ fi
+done
+
+# Copy SILK fixed-point encoder implementation
+echo "Copying SILK fixed-point encoder implementation..."
+if [ -d "$PROJECT_ROOT/silk/fixed" ]; then
+ find "$PROJECT_ROOT/silk/fixed" -name "*.c" -exec cp {} "$SCRIPT_DIR/silk/fixed/" \;
+ find "$PROJECT_ROOT/silk/fixed" -name "*.h" -exec cp {} "$SCRIPT_DIR/silk/fixed/" \;
+ echo " Copied SILK fixed-point encoder sources and headers"
+fi
+
+# Copy SILK float encoder implementation (encode_frame_FLP.c should already exist)
+echo "Copying SILK float encoder implementation..."
+if [ -f "$PROJECT_ROOT/silk/float/encode_frame_FLP.c" ]; then
+ cp "$PROJECT_ROOT/silk/float/encode_frame_FLP.c" "$SCRIPT_DIR/silk/float/"
+ echo " Copied: silk/float/encode_frame_FLP.c"
+fi
+
+echo ""
+echo "=========================================="
+echo "Encoder source files copied successfully!"
+echo "=========================================="
+echo ""
+echo "Next steps:"
+echo " 1. Review copied files"
+echo " 2. Run: make -f Makefile.libopus"
+echo " 3. This will create libopus_min.a with encoder support"
+echo ""
--- /dev/null
+#!/bin/bash
+# Script to copy missing header files needed for encoder support
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
+
+echo "Copying missing header files..."
+
+# Copy SILK float headers
+if [ -d "$PROJECT_ROOT/silk/float" ]; then
+ find "$PROJECT_ROOT/silk/float" -name "*.h" -exec cp {} "$SCRIPT_DIR/silk/float/" \;
+ echo " Copied SILK float headers"
+fi
+
+# Copy SILK fixed headers
+if [ -d "$PROJECT_ROOT/silk/fixed" ]; then
+ find "$PROJECT_ROOT/silk/fixed" -name "*.h" -exec cp {} "$SCRIPT_DIR/silk/fixed/" \;
+ echo " Copied SILK fixed headers"
+fi
+
+echo "Done!"
int opus_frame_to_pcm_decode_file(const char *input_file, int sample_rate, int channels,
const char *output_file);
+/**
+ * @brief Encode PCM buffer (in-memory) to a single Opus packet. No file I/O.
+ *
+ * @param pcm Input: interleaved 16-bit PCM (little-endian).
+ * @param pcm_samples_per_channel Number of samples per channel (e.g. 320 for 20ms @ 16kHz).
+ * @param sample_rate Sample rate in Hz (e.g. 16000/48000).
+ * @param channels Channel count (1=mono, 2=stereo).
+ * @param bitrate Target bitrate in bps (e.g. 64000).
+ * @param application Opus application: 0=VOIP, 1=AUDIO, 2=RESTRICTED_LOWDELAY.
+ * @param out_packet Output buffer for encoded Opus packet.
+ * @param out_packet_max_len Capacity of out_packet in bytes.
+ * @param out_encoded_len [out] Number of bytes written to out_packet. May be NULL.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int opus_pcm_to_frame_encode_packet(const short *pcm, int pcm_samples_per_channel,
+ int sample_rate, int channels,
+ int bitrate, int application,
+ unsigned char *out_packet, int out_packet_max_len,
+ int *out_encoded_len);
+
+/**
+ * @brief Encode PCM file to a single Opus frame file.
+ *
+ * @param input_file Input file path containing 16-bit little-endian PCM.
+ * @param sample_rate Sample rate in Hz (e.g. 16000/48000).
+ * @param channels Channel count (1=mono, 2=stereo).
+ * @param bitrate Target bitrate in bps (e.g. 64000).
+ * @param application Opus application: 0=VOIP, 1=AUDIO, 2=RESTRICTED_LOWDELAY.
+ * @param output_file Output Opus file path. If NULL, write to stdout.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int opus_pcm_to_frame_encode_file(const char *input_file, int sample_rate, int channels,
+ int bitrate, int application, const char *output_file);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+ opus_int32 err_Q24[], /* O Quantization errors [K] */
+ const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */
+ const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */
+ const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */
+ const opus_int K, /* I Number of codebook vectors */
+ const opus_int LPC_order /* I Number of LPCs */
+)
+{
+ opus_int i, m;
+ opus_int32 diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24;
+ const opus_int16 *w_Q9_ptr;
+ const opus_uint8 *cb_Q8_ptr;
+
+ celt_assert( ( LPC_order & 1 ) == 0 );
+
+ /* Loop over codebook */
+ cb_Q8_ptr = pCB_Q8;
+ w_Q9_ptr = pWght_Q9;
+ for( i = 0; i < K; i++ ) {
+ sum_error_Q24 = 0;
+ pred_Q24 = 0;
+ for( m = LPC_order-2; m >= 0; m -= 2 ) {
+ /* Compute weighted absolute predictive quantization error for index m + 1 */
+ diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m + 1 ], (opus_int32)cb_Q8_ptr[ m + 1 ], 7 ); /* range: [ -32767 : 32767 ]*/
+ diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m + 1 ] );
+ sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) );
+ pred_Q24 = diffw_Q24;
+
+ /* Compute weighted absolute predictive quantization error for index m */
+ diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)cb_Q8_ptr[ m ], 7 ); /* range: [ -32767 : 32767 ]*/
+ diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m ] );
+ sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) );
+ pred_Q24 = diffw_Q24;
+
+ silk_assert( sum_error_Q24 >= 0 );
+ }
+ err_Q24[ i ] = sum_error_Q24;
+ cb_Q8_ptr += LPC_order;
+ w_Q9_ptr += LPC_order;
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */
+ opus_int8 indices[], /* O Quantization indices [ order ] */
+ const opus_int16 x_Q10[], /* I Input [ order ] */
+ const opus_int16 w_Q5[], /* I Weights [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */
+ const opus_uint8 ec_rates_Q5[], /* I Rates [] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */
+ const opus_int32 mu_Q20, /* I R/D tradeoff */
+ const opus_int16 order /* I Number of input values */
+)
+{
+ opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10;
+ opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5;
+ opus_int16 out0_Q10, out1_Q10;
+ opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25;
+ opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ];
+ opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
+ const opus_uint8 *rates_Q5;
+
+ opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
+ opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT];
+
+ for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++)
+ {
+ out0_Q10 = silk_LSHIFT( i, 10 );
+ out1_Q10 = silk_ADD16( out0_Q10, 1024 );
+ if( i > 0 ) {
+ out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( i == 0 ) {
+ out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( i == -1 ) {
+ out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else {
+ out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ }
+ out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 );
+ out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 );
+ }
+
+ silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */
+
+ nStates = 1;
+ RD_Q25[ 0 ] = 0;
+ prev_out_Q10[ 0 ] = 0;
+ for( i = order - 1; i >= 0; i-- ) {
+ rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ];
+ in_Q10 = x_Q10[ i ];
+ for( j = 0; j < nStates; j++ ) {
+ pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 );
+ res_Q10 = silk_SUB16( in_Q10, pred_Q10 );
+ ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 );
+ ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 );
+ ind[ j ][ i ] = (opus_int8)ind_tmp;
+
+ /* compute outputs for ind_tmp and ind_tmp + 1 */
+ out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
+ out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ];
+
+ out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 );
+ out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 );
+ prev_out_Q10[ j ] = out0_Q10;
+ prev_out_Q10[ j + nStates ] = out1_Q10;
+
+ /* compute RD for ind_tmp and ind_tmp + 1 */
+ if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) {
+ if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) {
+ rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+ rate1_Q5 = 280;
+ } else {
+ rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp );
+ rate1_Q5 = silk_ADD16( rate0_Q5, 43 );
+ }
+ } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+ if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) {
+ rate0_Q5 = 280;
+ rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+ } else {
+ rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp );
+ rate1_Q5 = silk_SUB16( rate0_Q5, 43 );
+ }
+ } else {
+ rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+ rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+ }
+ RD_tmp_Q25 = RD_Q25[ j ];
+ diff_Q10 = silk_SUB16( in_Q10, out0_Q10 );
+ RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 );
+ diff_Q10 = silk_SUB16( in_Q10, out1_Q10 );
+ RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 );
+ }
+
+ if( nStates <= NLSF_QUANT_DEL_DEC_STATES/2 ) {
+ /* double number of states and copy */
+ for( j = 0; j < nStates; j++ ) {
+ ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1;
+ }
+ nStates = silk_LSHIFT( nStates, 1 );
+ for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ ind[ j ][ i ] = ind[ j - nStates ][ i ];
+ }
+ } else {
+ /* sort lower and upper half of RD_Q25, pairwise */
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) {
+ RD_max_Q25[ j ] = RD_Q25[ j ];
+ RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ RD_Q25[ j ] = RD_min_Q25[ j ];
+ RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ];
+ /* swap prev_out values */
+ out0_Q10 = prev_out_Q10[ j ];
+ prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10;
+ ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES;
+ } else {
+ RD_min_Q25[ j ] = RD_Q25[ j ];
+ RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ ind_sort[ j ] = j;
+ }
+ }
+ /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */
+ /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */
+ while( 1 ) {
+ min_max_Q25 = silk_int32_MAX;
+ max_min_Q25 = 0;
+ ind_min_max = 0;
+ ind_max_min = 0;
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( min_max_Q25 > RD_max_Q25[ j ] ) {
+ min_max_Q25 = RD_max_Q25[ j ];
+ ind_min_max = j;
+ }
+ if( max_min_Q25 < RD_min_Q25[ j ] ) {
+ max_min_Q25 = RD_min_Q25[ j ];
+ ind_max_min = j;
+ }
+ }
+ if( min_max_Q25 >= max_min_Q25 ) {
+ break;
+ }
+ /* copy ind_min_max to ind_max_min */
+ ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES;
+ RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+ prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+ RD_min_Q25[ ind_max_min ] = 0;
+ RD_max_Q25[ ind_min_max ] = silk_int32_MAX;
+ silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) );
+ }
+ /* increment index if it comes from the upper half */
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+ }
+ }
+ }
+
+ /* last sample: find winner, copy indices and return RD value */
+ ind_tmp = 0;
+ min_Q25 = silk_int32_MAX;
+ for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( min_Q25 > RD_Q25[ j ] ) {
+ min_Q25 = RD_Q25[ j ];
+ ind_tmp = j;
+ }
+ }
+ for( j = 0; j < order; j++ ) {
+ indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ];
+ silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ }
+ indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+ silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ silk_assert( min_Q25 >= 0 );
+ return min_Q25;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/***********************/
+/* NLSF vector encoder */
+/***********************/
+opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */
+ const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */
+ const opus_int nSurvivors, /* I Max survivors after first stage */
+ const opus_int signalType /* I Signal type: 0/1/2 */
+)
+{
+ opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7;
+ opus_int32 W_tmp_Q9, ret;
+ VARDECL( opus_int32, err_Q24 );
+ VARDECL( opus_int32, RD_Q25 );
+ VARDECL( opus_int, tempIndices1 );
+ VARDECL( opus_int8, tempIndices2 );
+ opus_int16 res_Q10[ MAX_LPC_ORDER ];
+ opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ];
+ opus_int16 W_adj_Q5[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ const opus_uint8 *pCB_element, *iCDF_ptr;
+ const opus_int16 *pCB_Wght_Q9;
+ SAVE_STACK;
+
+ celt_assert( signalType >= 0 && signalType <= 2 );
+ silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 );
+
+ /* NLSF stabilization */
+ silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+
+ /* First stage: VQ */
+ ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 );
+ silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order );
+
+ /* Sort the quantization errors */
+ ALLOC( tempIndices1, nSurvivors, opus_int );
+ silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors );
+
+ ALLOC( RD_Q25, nSurvivors, opus_int32 );
+ ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 );
+
+ /* Loop over survivors */
+ for( s = 0; s < nSurvivors; s++ ) {
+ ind1 = tempIndices1[ s ];
+
+ /* Residual after first stage */
+ pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ];
+ pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ];
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 );
+ W_tmp_Q9 = pCB_Wght_Q9[ i ];
+ res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 );
+ W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 );
+ }
+
+ /* Unpack entropy table indices and predictor for current CB1 index */
+ silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 );
+
+ /* Trellis quantizer */
+ RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix,
+ psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order );
+
+ /* Add rate for first stage */
+ iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ];
+ if( ind1 == 0 ) {
+ prob_Q8 = 256 - iCDF_ptr[ ind1 ];
+ } else {
+ prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ];
+ }
+ bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 );
+ RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) );
+ }
+
+ /* Find the lowest rate-distortion error */
+ silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 );
+
+ NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ];
+ silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) );
+
+ /* Decode */
+ silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB );
+
+ ret = RD_Q25[ 0 ];
+ RESTORE_STACK;
+ return ret;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+
+
+static OPUS_INLINE void silk_nsq_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int16 x16[], /* I input */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+);
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ int arch /* I Architecture */
+);
+#endif
+
+void silk_NSQ_c
+(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int16 x16[], /* I Input */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 *PredCoef_Q12, /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int k, lag, start_idx, LSF_interpolation_flag;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ SAVE_STACK;
+
+ NSQ->rand_seed = psIndices->Seed;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
+ B_Q14 = <PCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ celt_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+ NSQ->rewhite_flag = 1;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ }
+ }
+
+ silk_nsq_scale_states( psEncC, NSQ, x16, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
+
+ silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+ AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
+ offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch );
+
+ x16 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Update lagPrev for next frame */
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech and noise shaping signals */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/******************************/
+/* silk_noise_shape_quantizer */
+/******************************/
+
+#if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE
+#endif
+void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ int arch /* I Architecture */
+)
+{
+ opus_int i;
+ opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+ opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+ opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
+#ifdef silk_short_prediction_create_arch_coef
+ opus_int32 a_Q12_arch[MAX_LPC_ORDER];
+#endif
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ /* Set up short term AR state */
+ psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
+
+#ifdef silk_short_prediction_create_arch_coef
+ silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
+#endif
+
+ for( i = 0; i < length; i++ ) {
+ /* Generate dither */
+ NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
+
+ /* Short-term prediction */
+ LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q13 = 2;
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q13 = 0;
+ }
+
+ /* Noise shape feedback */
+ celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(&NSQ->sDiff_shp_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch);
+
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
+
+ n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
+ n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 );
+
+ celt_assert( lag > 0 || signalType != TYPE_VOICED );
+
+ /* Combine prediction and noise shaping signals */
+ tmp1 = silk_SUB32_ovflw( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */
+ tmp1 = silk_SUB32_ovflw( tmp1, n_LF_Q12 ); /* Q12 */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q13 = silk_SMULWB( silk_ADD_SAT32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
+ shp_lag_ptr++;
+
+ tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */
+ tmp1 = silk_ADD32_ovflw( tmp2, silk_LSHIFT32( tmp1, 1 ) ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */
+ } else {
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */
+ }
+
+ r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if( NSQ->rand_seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if (Lambda_Q10 > 2048) {
+ /* For aggressive RDO, the bias becomes more than one pulse. */
+ int rdo_offset = Lambda_Q10/2 - 512;
+ if (q1_Q10 > rdo_offset) {
+ q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 );
+ } else if (q1_Q10 < -rdo_offset) {
+ q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 );
+ } else if (q1_Q10 < 0) {
+ q1_Q0 = -1;
+ } else {
+ q1_Q0 = 0;
+ }
+ }
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* Q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 );
+
+ if( rd2_Q20 < rd1_Q20 ) {
+ q1_Q10 = q2_Q10;
+ }
+
+ pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
+
+ /* Excitation */
+ exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
+ if ( NSQ->rand_seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
+ xq_Q14 = silk_ADD32_ovflw( LPC_exc_Q14, silk_LSHIFT32( LPC_pred_Q10, 4 ) );
+
+ /* Scale XQ back to normal level before saving */
+ xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) );
+
+ /* Update states */
+ psLPC_Q14++;
+ *psLPC_Q14 = xq_Q14;
+ NSQ->sDiff_shp_Q14 = silk_SUB32_ovflw( xq_Q14, silk_LSHIFT32( x_sc_Q10[ i ], 4 ) );
+ sLF_AR_shp_Q14 = silk_SUB32_ovflw( NSQ->sDiff_shp_Q14, silk_LSHIFT32( n_AR_Q12, 2 ) );
+ NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB32_ovflw(sLF_AR_shp_Q14, silk_LSHIFT32(n_LF_Q12, 2));
+ sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Make dither dependent on quantized signal */
+ NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
+ }
+
+ /* Update LPC synth buffer */
+ silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+}
+
+static OPUS_INLINE void silk_nsq_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int16 x16[], /* I input */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+)
+{
+ opus_int i, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Scale input */
+ inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 );
+ for( i = 0; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 );
+ }
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+
+ /* Scale long-term shaping state */
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
+ NSQ->sDiff_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sDiff_shp_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+#include "NSQ.h"
+
+
+typedef struct {
+ opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+ opus_int32 RandState[ DECISION_DELAY ];
+ opus_int32 Q_Q10[ DECISION_DELAY ];
+ opus_int32 Xq_Q14[ DECISION_DELAY ];
+ opus_int32 Pred_Q15[ DECISION_DELAY ];
+ opus_int32 Shape_Q14[ DECISION_DELAY ];
+ opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_AR_Q14;
+ opus_int32 Diff_Q14;
+ opus_int32 Seed;
+ opus_int32 SeedInit;
+ opus_int32 RD_Q10;
+} NSQ_del_dec_struct;
+
+typedef struct {
+ opus_int32 Q_Q10;
+ opus_int32 RD_Q10;
+ opus_int32 xq_Q14;
+ opus_int32 LF_AR_Q14;
+ opus_int32 Diff_Q14;
+ opus_int32 sLTP_shp_Q14;
+ opus_int32 LPC_exc_Q14;
+} NSQ_sample_struct;
+
+typedef NSQ_sample_struct NSQ_sample_pair[ 2 ];
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int16 x16[], /* I Input */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+);
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */
+ opus_int decisionDelay, /* I */
+ int arch /* I */
+);
+
+void silk_NSQ_del_dec_c(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int16 x16[], /* I Input */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 *PredCoef_Q12, /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+ opus_int last_smple_idx, smpl_buf_idx, decisionDelay;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ opus_int32 RDmin_Q10, Gain_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ VARDECL( opus_int32, delayedGain_Q10 );
+ VARDECL( NSQ_del_dec_struct, psDelDec );
+ NSQ_del_dec_struct *psDD;
+ SAVE_STACK;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ /* Initialize delayed decision states */
+ ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
+ silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
+ for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psDD->Seed = ( k + psIndices->Seed ) & 3;
+ psDD->SeedInit = psDD->Seed;
+ psDD->RD_Q10 = 0;
+ psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14;
+ psDD->Diff_Q14 = NSQ->sDiff_shp_Q14;
+ psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
+ silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
+ }
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+ smpl_buf_idx = 0; /* index of oldest samples */
+
+ decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
+
+ /* For voiced frames limit the decision delay to lower than the pitch lag */
+ if( psIndices->signalType == TYPE_VOICED ) {
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
+ }
+ } else {
+ if( lag > 0 ) {
+ decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
+ }
+ }
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ subfr = 0;
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
+ B_Q14 = <PCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ if( k == 2 ) {
+ /* RESET DELAYED DECISIONS */
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ i ].RD_Q10;
+ Winner_ind = i;
+ }
+ }
+ for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( i != Winner_ind ) {
+ psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
+ silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY;
+ if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+
+ subfr = 0;
+ }
+
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ celt_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch );
+
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ NSQ->rewhite_flag = 1;
+ }
+ }
+
+ silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k,
+ psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
+
+ silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
+ delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ],
+ Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder,
+ psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch );
+
+ x16 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ k ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ psIndices->Seed = psDD->SeedInit;
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY;
+ if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY;
+
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+ silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
+
+ /* Update states */
+ NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
+ NSQ->sDiff_shp_Q14 = psDD->Diff_Q14;
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech signal */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */
+ opus_int decisionDelay, /* I */
+ int arch /* I */
+)
+{
+ opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+ opus_int32 Winner_rand_state;
+ opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+ opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+ opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+#ifdef silk_short_prediction_create_arch_coef
+ opus_int32 a_Q12_arch[MAX_LPC_ORDER];
+#endif
+
+ VARDECL( NSQ_sample_pair, psSampleState );
+ NSQ_del_dec_struct *psDD;
+ NSQ_sample_struct *psSS;
+ SAVE_STACK;
+
+ celt_assert( nStatesDelayedDecision > 0 );
+ ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+#ifdef silk_short_prediction_create_arch_coef
+ silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder);
+#endif
+
+ for( i = 0; i < length; i++ ) {
+ /* Perform common calculations used in all states */
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q14 = 2;
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q14 = 0;
+ }
+
+ /* Long-term shaping */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q14 = silk_SMULWB( silk_ADD_SAT32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */
+ shp_lag_ptr++;
+ } else {
+ n_LTP_Q14 = 0;
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ /* Delayed decision state */
+ psDD = &psDelDec[ k ];
+
+ /* Sample state */
+ psSS = psSampleState[ k ];
+
+ /* Generate dither */
+ psDD->Seed = silk_RAND( psDD->Seed );
+
+ /* Pointer used in short term prediction and shaping */
+ psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+ /* Short-term prediction */
+ LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch);
+ LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
+
+ /* Noise shape feedback */
+ celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( psDD->Diff_Q14, psDD->sAR2_Q14[ 0 ], warping_Q16 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], silk_SUB32_ovflw(psDD->sAR2_Q14[ 1 ], tmp2), warping_Q16 );
+ psDD->sAR2_Q14[ 0 ] = tmp2;
+ n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
+ /* Loop over allpass sections */
+ for( j = 2; j < shapingLPCOrder; j += 2 ) {
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], silk_SUB32_ovflw(psDD->sAR2_Q14[ j + 0 ], tmp1), warping_Q16 );
+ psDD->sAR2_Q14[ j - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], silk_SUB32_ovflw(psDD->sAR2_Q14[ j + 1 ], tmp2), warping_Q16 );
+ psDD->sAR2_Q14[ j + 0 ] = tmp2;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
+ }
+ psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */
+
+ n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */
+
+ /* Input minus prediction plus noise feedback */
+ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
+ tmp1 = silk_ADD_SAT32( n_AR_Q14, n_LF_Q14 ); /* Q14 */
+ tmp2 = silk_ADD32_ovflw( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */
+ tmp1 = silk_SUB_SAT32( tmp2, tmp1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */
+
+ r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( psDD->Seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if (Lambda_Q10 > 2048) {
+ /* For aggressive RDO, the bias becomes more than one pulse. */
+ int rdo_offset = Lambda_Q10/2 - 512;
+ if (q1_Q10 > rdo_offset) {
+ q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 );
+ } else if (q1_Q10 < -rdo_offset) {
+ q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 );
+ } else if (q1_Q10 < 0) {
+ q1_Q0 = -1;
+ } else {
+ q1_Q0 = 0;
+ }
+ }
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+ if( rd1_Q10 < rd2_Q10 ) {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 0 ].Q_Q10 = q1_Q10;
+ psSS[ 1 ].Q_Q10 = q2_Q10;
+ } else {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 0 ].Q_Q10 = q2_Q10;
+ psSS[ 1 ].Q_Q10 = q1_Q10;
+ }
+
+ /* Update states for best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32_ovflw( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ psSS[ 0 ].Diff_Q14 = silk_SUB32_ovflw( xq_Q14, silk_LSHIFT32( x_Q10[ i ], 4 ) );
+ sLF_AR_shp_Q14 = silk_SUB32_ovflw( psSS[ 0 ].Diff_Q14, n_AR_Q14 );
+ psSS[ 0 ].sLTP_shp_Q14 = silk_SUB_SAT32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 0 ].xq_Q14 = xq_Q14;
+
+ /* Update states for second best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32_ovflw( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ psSS[ 1 ].Diff_Q14 = silk_SUB32_ovflw( xq_Q14, silk_LSHIFT32( x_Q10[ i ], 4 ) );
+ sLF_AR_shp_Q14 = silk_SUB32_ovflw( psSS[ 1 ].Diff_Q14, n_AR_Q14 );
+ psSS[ 1 ].sLTP_shp_Q14 = silk_SUB_SAT32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 1 ].xq_Q14 = xq_Q14;
+ }
+
+ *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY;
+ if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY;
+ last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY;
+
+ /* Find winner */
+ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Increase RD values of expired states */
+ Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+ psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+ psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+ silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Find worst in first set and best in second set */
+ RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10;
+ RDmax_ind = 0;
+ RDmin_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ /* find worst in first set */
+ if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+ RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ RDmax_ind = k;
+ }
+ /* find best in second set */
+ if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10;
+ RDmin_ind = k;
+ }
+ }
+
+ /* Replace a state if best from second set outperforms worst in first set */
+ if( RDmin_Q10 < RDmax_Q10 ) {
+ silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+ ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+ silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+ }
+
+ /* Write samples from winner to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ if( subfr > 0 || i >= decisionDelay ) {
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+ sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ];
+ }
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Update states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psSS = &psSampleState[ k ][ 0 ];
+ psDD->LF_AR_Q14 = psSS->LF_AR_Q14;
+ psDD->Diff_Q14 = psSS->Diff_Q14;
+ psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+ psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14;
+ psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10;
+ psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+ psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14;
+ psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+ psDD->RandState[ *smpl_buf_idx ] = psDD->Seed;
+ psDD->RD_Q10 = psSS->RD_Q10;
+ }
+ delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10;
+ }
+ /* Update LPC states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
+#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int16 x16[], /* I Input */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+)
+{
+ opus_int i, k, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26;
+ NSQ_del_dec_struct *psDD;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Scale input */
+ inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 );
+ for( i = 0; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 );
+ }
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+
+ /* Scale long-term shaping state */
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+
+ /* Scale scalar states */
+ psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
+ psDD->Diff_Q14 = silk_SMULWW( gain_adj_Q16, psDD->Diff_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
+ }
+ for( i = 0; i < DECISION_DELAY; i++ ) {
+ psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] );
+ psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
+ }
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Silk VAD noise level estimation */
+# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+);
+#endif
+
+/**********************************/
+/* Initialization of the Silk VAD */
+/**********************************/
+opus_int silk_VAD_Init( /* O Return value, 0 if success */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+)
+{
+ opus_int b, ret = 0;
+
+ /* reset state memory */
+ silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) );
+
+ /* init noise levels */
+ /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 );
+ }
+
+ /* Initialize state */
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] );
+ psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] );
+ }
+ psSilk_VAD->counter = 15;
+
+ /* init smoothed energy-to-noise ratio*/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */
+ }
+
+ return( ret );
+}
+
+/* Weighting factors for tilt measure */
+static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
+
+/***************************************/
+/* Get the speech activity level in Q8 */
+/***************************************/
+opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ const opus_int16 pIn[] /* I PCM input */
+)
+{
+ opus_int SA_Q15, pSNR_dB_Q7, input_tilt;
+ opus_int decimated_framelength1, decimated_framelength2;
+ opus_int decimated_framelength;
+ opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
+ opus_int32 sumSquared, smooth_coef_Q16;
+ opus_int16 HPstateTmp;
+ VARDECL( opus_int16, X );
+ opus_int32 Xnrg[ VAD_N_BANDS ];
+ opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
+ opus_int32 speech_nrg, x_tmp;
+ opus_int X_offset[ VAD_N_BANDS ];
+ opus_int ret = 0;
+ silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
+ SAVE_STACK;
+
+ /* Safety checks */
+ silk_assert( VAD_N_BANDS == 4 );
+ celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
+ celt_assert( psEncC->frame_length <= 512 );
+ celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
+
+ /***********************/
+ /* Filter and Decimate */
+ /***********************/
+ decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
+ decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
+ /* Decimate into 4 bands:
+ 0 L 3L L 3L 5L
+ - -- - -- --
+ 8 8 2 4 4
+
+ [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz |
+
+ They're arranged to allow the minimal ( frame_length / 4 ) extra
+ scratch space during the downsampling process */
+ X_offset[ 0 ] = 0;
+ X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
+ X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
+ X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
+ ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
+
+ /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
+ silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ],
+ X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
+
+ /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
+ X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
+
+ /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
+ X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
+
+ /*********************************************/
+ /* HP filter on lowest band (differentiator) */
+ /*********************************************/
+ X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
+ HPstateTmp = X[ decimated_framelength - 1 ];
+ for( i = decimated_framelength - 1; i > 0; i-- ) {
+ X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 );
+ X[ i ] -= X[ i - 1 ];
+ }
+ X[ 0 ] -= psSilk_VAD->HPstate;
+ psSilk_VAD->HPstate = HPstateTmp;
+
+ /*************************************/
+ /* Calculate the energy in each band */
+ /*************************************/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Find the decimated framelength in the non-uniformly divided bands */
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
+
+ /* Split length into subframe lengths */
+ dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
+ dec_subframe_offset = 0;
+
+ /* Compute energy per sub-frame */
+ /* initialize with summed energy of last subframe */
+ Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
+ for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
+ sumSquared = 0;
+ for( i = 0; i < dec_subframe_length; i++ ) {
+ /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */
+ /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */
+ x_tmp = silk_RSHIFT(
+ X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
+ sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
+
+ /* Safety check */
+ silk_assert( sumSquared >= 0 );
+ }
+
+ /* Add/saturate summed energy of current subframe */
+ if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
+ } else {
+ /* Look-ahead subframe */
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
+ }
+
+ dec_subframe_offset += dec_subframe_length;
+ }
+ psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
+ }
+
+ /********************/
+ /* Noise estimation */
+ /********************/
+ silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
+
+ /***********************************************/
+ /* Signal-plus-noise to noise ratio estimation */
+ /***********************************************/
+ sumSquared = 0;
+ input_tilt = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
+ if( speech_nrg > 0 ) {
+ /* Divide, with sufficient resolution */
+ if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
+ }
+
+ /* Convert to log domain */
+ SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
+
+ /* Sum-of-squares */
+ sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */
+
+ /* Tilt measure */
+ if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
+ /* Scale down SNR value for small subband speech energies */
+ SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
+ }
+ input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = 256;
+ }
+ }
+
+ /* Mean-of-squares */
+ sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
+
+ /* Root-mean-square approximation, scale to dBs, and write to output pointer */
+ pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
+
+ /*********************************/
+ /* Speech Probability Estimation */
+ /*********************************/
+ SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
+
+ /**************************/
+ /* Frequency Tilt Measure */
+ /**************************/
+ psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
+
+ /**************************************************/
+ /* Scale the sigmoid output based on power levels */
+ /**************************************************/
+ speech_nrg = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
+ speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
+ }
+
+ if( psEncC->frame_length == 20 * psEncC->fs_kHz ) {
+ speech_nrg = silk_RSHIFT32( speech_nrg, 1 );
+ }
+ /* Power scaling */
+ if( speech_nrg <= 0 ) {
+ SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
+ } else if( speech_nrg < 16384 ) {
+ speech_nrg = silk_LSHIFT32( speech_nrg, 16 );
+
+ /* square-root */
+ speech_nrg = silk_SQRT_APPROX( speech_nrg );
+ SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
+ }
+
+ /* Copy the resulting speech activity in Q8 */
+ psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
+
+ /***********************************/
+ /* Energy Level and SNR estimation */
+ /***********************************/
+ /* Smoothing coefficient */
+ smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
+
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ smooth_coef_Q16 >>= 1;
+ }
+
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* compute smoothed energy-to-noise ratio per band */
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
+ NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
+
+ /* signal to noise ratio in dB per band */
+ SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
+ /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
+ psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
+ }
+
+ RESTORE_STACK;
+ return( ret );
+}
+
+/**************************/
+/* Noise level estimation */
+/**************************/
+# if !defined(OPUS_X86_MAY_HAVE_SSE4_1)
+static OPUS_INLINE
+#endif
+void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+)
+{
+ opus_int k;
+ opus_int32 nl, nrg, inv_nrg;
+ opus_int coef, min_coef;
+
+ /* Initially faster smoothing */
+ if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */
+ min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 );
+ /* Increment frame counter */
+ psSilk_VAD->counter++;
+ } else {
+ min_coef = 0;
+ }
+
+ for( k = 0; k < VAD_N_BANDS; k++ ) {
+ /* Get old noise level estimate for current band */
+ nl = psSilk_VAD->NL[ k ];
+ silk_assert( nl >= 0 );
+
+ /* Add bias */
+ nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] );
+ silk_assert( nrg > 0 );
+
+ /* Invert energies */
+ inv_nrg = silk_DIV32( silk_int32_MAX, nrg );
+ silk_assert( inv_nrg >= 0 );
+
+ /* Less update when subband energy is high */
+ if( nrg > silk_LSHIFT( nl, 3 ) ) {
+ coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
+ } else if( nrg < nl ) {
+ coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
+ } else {
+ coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 );
+ }
+
+ /* Initially faster smoothing */
+ coef = silk_max_int( coef, min_coef );
+
+ /* Smooth inverse energies */
+ psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef );
+ silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 );
+
+ /* Compute noise level by inverting again */
+ nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] );
+ silk_assert( nl >= 0 );
+
+ /* Limit noise levels (guarantee 7 bits of head room) */
+ nl = silk_min( nl, 0x00FFFFFF );
+
+ /* Store as part of state */
+ psSilk_VAD->NL[ k ] = nl;
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+void silk_VQ_WMat_EC_c(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *res_nrg_Q15, /* O best residual energy */
+ opus_int32 *rate_dist_Q8, /* O best total bitrate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int32 *XX_Q17, /* I correlation matrix */
+ const opus_int32 *xX_Q17, /* I correlation vector */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int subfr_len, /* I number of samples per subframe */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ const opus_int L /* I number of vectors in codebook */
+)
+{
+ opus_int k, gain_tmp_Q7;
+ const opus_int8 *cb_row_Q7;
+ opus_int32 neg_xX_Q24[ 5 ];
+ opus_int32 sum1_Q15, sum2_Q24;
+ opus_int32 bits_res_Q8, bits_tot_Q8;
+
+ /* Negate and convert to new Q domain */
+ neg_xX_Q24[ 0 ] = -silk_LSHIFT32( xX_Q17[ 0 ], 7 );
+ neg_xX_Q24[ 1 ] = -silk_LSHIFT32( xX_Q17[ 1 ], 7 );
+ neg_xX_Q24[ 2 ] = -silk_LSHIFT32( xX_Q17[ 2 ], 7 );
+ neg_xX_Q24[ 3 ] = -silk_LSHIFT32( xX_Q17[ 3 ], 7 );
+ neg_xX_Q24[ 4 ] = -silk_LSHIFT32( xX_Q17[ 4 ], 7 );
+
+ /* Loop over codebook */
+ *rate_dist_Q8 = silk_int32_MAX;
+ *res_nrg_Q15 = silk_int32_MAX;
+ cb_row_Q7 = cb_Q7;
+ /* If things go really bad, at least *ind is set to something safe. */
+ *ind = 0;
+ for( k = 0; k < L; k++ ) {
+ opus_int32 penalty;
+ gain_tmp_Q7 = cb_gain_Q7[k];
+ /* Weighted rate */
+ /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */
+ sum1_Q15 = SILK_FIX_CONST( 1.001, 15 );
+
+ /* Penalty for too large gain */
+ penalty = silk_LSHIFT32( silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 11 );
+
+ /* first row of XX_Q17 */
+ sum2_Q24 = silk_MLA( neg_xX_Q24[ 0 ], XX_Q17[ 1 ], cb_row_Q7[ 1 ] );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 2 ], cb_row_Q7[ 2 ] );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 3 ], cb_row_Q7[ 3 ] );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 4 ], cb_row_Q7[ 4 ] );
+ sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 0 ], cb_row_Q7[ 0 ] );
+ sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 0 ] );
+
+ /* second row of XX_Q17 */
+ sum2_Q24 = silk_MLA( neg_xX_Q24[ 1 ], XX_Q17[ 7 ], cb_row_Q7[ 2 ] );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 8 ], cb_row_Q7[ 3 ] );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 9 ], cb_row_Q7[ 4 ] );
+ sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 6 ], cb_row_Q7[ 1 ] );
+ sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 1 ] );
+
+ /* third row of XX_Q17 */
+ sum2_Q24 = silk_MLA( neg_xX_Q24[ 2 ], XX_Q17[ 13 ], cb_row_Q7[ 3 ] );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 14 ], cb_row_Q7[ 4 ] );
+ sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 12 ], cb_row_Q7[ 2 ] );
+ sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 2 ] );
+
+ /* fourth row of XX_Q17 */
+ sum2_Q24 = silk_MLA( neg_xX_Q24[ 3 ], XX_Q17[ 19 ], cb_row_Q7[ 4 ] );
+ sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 18 ], cb_row_Q7[ 3 ] );
+ sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 3 ] );
+
+ /* last row of XX_Q17 */
+ sum2_Q24 = silk_LSHIFT32( neg_xX_Q24[ 4 ], 1 );
+ sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 24 ], cb_row_Q7[ 4 ] );
+ sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 4 ] );
+
+ /* find best */
+ if( sum1_Q15 >= 0 ) {
+ /* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */
+ bits_res_Q8 = silk_SMULBB( subfr_len, silk_lin2log( sum1_Q15 + penalty) - (15 << 7) );
+ /* In the following line we reduce the codelength component by half ("-1"); seems to slightly improve quality */
+ bits_tot_Q8 = silk_ADD_LSHIFT32( bits_res_Q8, cl_Q5[ k ], 3-1 );
+ if( bits_tot_Q8 <= *rate_dist_Q8 ) {
+ *rate_dist_Q8 = bits_tot_Q8;
+ *res_nrg_Q15 = sum1_Q15 + penalty;
+ *ind = (opus_int8)k;
+ *gain_Q7 = gain_tmp_Q7;
+ }
+ }
+
+ /* Go to next cbk vector */
+ cb_row_Q7 += LTP_ORDER;
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Coefficients for 2-band filter bank based on first-order allpass filters */
+static const opus_int16 A_fb1_20 = 5394 << 1;
+static const opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
+
+/* Split signal into two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+ const opus_int16 *in, /* I Input signal [N] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *outL, /* O Low band [N/2] */
+ opus_int16 *outH, /* O High band [N/2] */
+ const opus_int32 N /* I Number of input samples */
+)
+{
+ opus_int k, N2 = silk_RSHIFT( N, 1 );
+ opus_int32 in32, X, Y, out_1, out_2;
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < N2; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+ /* All-pass section for even input sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMLAWB( Y, Y, A_fb1_21 );
+ out_1 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+ /* All-pass section for odd input sample, and add to output of previous section */
+ Y = silk_SUB32( in32, S[ 1 ] );
+ X = silk_SMULWB( Y, A_fb1_20 );
+ out_2 = silk_ADD32( S[ 1 ], X );
+ S[ 1 ] = silk_ADD32( in32, X );
+
+ /* Add/subtract, convert back to int16 and store to output */
+ outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) );
+ outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) );
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "control.h"
+#include "errors.h"
+
+/* Check encoder control struct */
+opus_int check_control_input(
+ silk_EncControlStruct *encControl /* I Control structure */
+)
+{
+ celt_assert( encControl != NULL );
+
+ if( ( ( encControl->API_sampleRate != 8000 ) &&
+ ( encControl->API_sampleRate != 12000 ) &&
+ ( encControl->API_sampleRate != 16000 ) &&
+ ( encControl->API_sampleRate != 24000 ) &&
+ ( encControl->API_sampleRate != 32000 ) &&
+ ( encControl->API_sampleRate != 44100 ) &&
+#ifdef ENABLE_QEXT
+ ( encControl->API_sampleRate != 96000 ) &&
+#endif
+ ( encControl->API_sampleRate != 48000 ) ) ||
+ ( ( encControl->desiredInternalSampleRate != 8000 ) &&
+ ( encControl->desiredInternalSampleRate != 12000 ) &&
+ ( encControl->desiredInternalSampleRate != 16000 ) ) ||
+ ( ( encControl->maxInternalSampleRate != 8000 ) &&
+ ( encControl->maxInternalSampleRate != 12000 ) &&
+ ( encControl->maxInternalSampleRate != 16000 ) ) ||
+ ( ( encControl->minInternalSampleRate != 8000 ) &&
+ ( encControl->minInternalSampleRate != 12000 ) &&
+ ( encControl->minInternalSampleRate != 16000 ) ) ||
+ ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) ||
+ ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) ||
+ ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) {
+ celt_assert( 0 );
+ return SILK_ENC_FS_NOT_SUPPORTED;
+ }
+ if( encControl->payloadSize_ms != 10 &&
+ encControl->payloadSize_ms != 20 &&
+ encControl->payloadSize_ms != 40 &&
+ encControl->payloadSize_ms != 60 ) {
+ celt_assert( 0 );
+ return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_LOSS_RATE;
+ }
+ if( encControl->useDTX < 0 || encControl->useDTX > 1 ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_DTX_SETTING;
+ }
+ if( encControl->useCBR < 0 || encControl->useCBR > 1 ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_CBR_SETTING;
+ }
+ if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_INBAND_FEC_SETTING;
+ }
+ if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->nChannelsInternal > encControl->nChannelsAPI ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->complexity < 0 || encControl->complexity > 10 ) {
+ celt_assert( 0 );
+ return SILK_ENC_INVALID_COMPLEXITY_SETTING;
+ }
+
+ return SILK_NO_ERROR;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+/* These tables hold SNR values divided by 21 (so they fit in 8 bits)
+ for different target bitrates spaced at 400 bps interval. The first
+ 10 values are omitted (0-4 kb/s) because they're all zeros.
+ These tables were obtained by running different SNRs through the
+ encoder and measuring the active bitrate. */
+static const unsigned char silk_TargetRate_NB_21[117 - 10] = {
+ 0, 15, 39, 52, 61, 68,
+ 74, 79, 84, 88, 92, 95, 99,102,105,108,111,114,117,119,122,124,
+ 126,129,131,133,135,137,139,142,143,145,147,149,151,153,155,157,
+ 158,160,162,163,165,167,168,170,171,173,174,176,177,179,180,182,
+ 183,185,186,187,189,190,192,193,194,196,197,199,200,201,203,204,
+ 205,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225,
+ 227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,248,
+ 249,250,252,253,255
+};
+
+static const unsigned char silk_TargetRate_MB_21[165 - 10] = {
+ 0, 0, 28, 43, 52, 59,
+ 65, 70, 74, 78, 81, 85, 87, 90, 93, 95, 98,100,102,105,107,109,
+ 111,113,115,116,118,120,122,123,125,127,128,130,131,133,134,136,
+ 137,138,140,141,143,144,145,147,148,149,151,152,153,154,156,157,
+ 158,159,160,162,163,164,165,166,167,168,169,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190,
+ 191,192,193,194,195,196,197,198,199,200,201,202,203,203,204,205,
+ 206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220,
+ 221,222,223,224,224,225,226,227,228,229,230,231,232,233,234,235,
+ 236,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,
+ 251,252,253,254,255
+};
+
+static const unsigned char silk_TargetRate_WB_21[201 - 10] = {
+ 0, 0, 0, 8, 29, 41,
+ 49, 56, 62, 66, 70, 74, 77, 80, 83, 86, 88, 91, 93, 95, 97, 99,
+ 101,103,105,107,108,110,112,113,115,116,118,119,121,122,123,125,
+ 126,127,129,130,131,132,134,135,136,137,138,140,141,142,143,144,
+ 145,146,147,148,149,150,151,152,153,154,156,157,158,159,159,160,
+ 161,162,163,164,165,166,167,168,169,170,171,171,172,173,174,175,
+ 176,177,177,178,179,180,181,181,182,183,184,185,185,186,187,188,
+ 189,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200,
+ 200,201,202,203,203,204,205,206,206,207,208,209,209,210,211,211,
+ 212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223,
+ 224,224,225,226,226,227,228,229,229,230,231,232,232,233,234,234,
+ 235,236,237,237,238,239,240,240,241,242,243,243,244,245,246,246,
+ 247,248,249,249,250,251,252,253,255
+};
+
+/* Control SNR of residual quantizer */
+opus_int silk_control_SNR(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ opus_int32 TargetRate_bps /* I Target max bitrate (bps) */
+)
+{
+ int id;
+ int bound;
+ const unsigned char *snr_table;
+
+ psEncC->TargetRate_bps = TargetRate_bps;
+ if( psEncC->nb_subfr == 2 ) {
+ TargetRate_bps -= 2000 + psEncC->fs_kHz/16;
+ }
+ if( psEncC->fs_kHz == 8 ) {
+ bound = sizeof(silk_TargetRate_NB_21);
+ snr_table = silk_TargetRate_NB_21;
+ } else if( psEncC->fs_kHz == 12 ) {
+ bound = sizeof(silk_TargetRate_MB_21);
+ snr_table = silk_TargetRate_MB_21;
+ } else {
+ bound = sizeof(silk_TargetRate_WB_21);
+ snr_table = silk_TargetRate_WB_21;
+ }
+ id = (TargetRate_bps+200)/400;
+ id = silk_min(id - 10, bound-1);
+ if( id <= 0 ) {
+ psEncC->SNR_dB_Q7 = 0;
+ } else {
+ psEncC->SNR_dB_Q7 = snr_table[id]*21;
+ }
+ return SILK_NO_ERROR;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl /* I Control structure */
+)
+{
+ opus_int fs_kHz;
+ opus_int orig_kHz;
+ opus_int32 fs_Hz;
+
+ orig_kHz = psEncC->fs_kHz;
+ /* Handle a bandwidth-switching reset where we need to be aware what the last sampling rate was. */
+ if( orig_kHz == 0 ) {
+ orig_kHz = psEncC->sLP.saved_fs_kHz;
+ }
+ fs_kHz = orig_kHz;
+ fs_Hz = silk_SMULBB( fs_kHz, 1000 );
+ if( fs_Hz == 0 ) {
+ /* Encoder has just been initialized */
+ fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz );
+ fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+ } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) {
+ /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */
+ fs_Hz = psEncC->API_fs_Hz;
+ fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz );
+ fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz );
+ fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+ } else {
+ /* State machine for the internal sampling rate switching */
+ if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) {
+ /* Stop transition phase */
+ psEncC->sLP.mode = 0;
+ }
+ if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) {
+ /* Check if we should switch down */
+ if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz )
+ {
+ /* Switch down */
+ if( psEncC->sLP.mode == 0 ) {
+ /* New transition */
+ psEncC->sLP.transition_frame_no = TRANSITION_FRAMES;
+
+ /* Reset transition filter state */
+ silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+ }
+ if( encControl->opusCanSwitch ) {
+ /* Stop transition phase */
+ psEncC->sLP.mode = 0;
+
+ /* Switch to a lower sample frequency */
+ fs_kHz = orig_kHz == 16 ? 12 : 8;
+ } else {
+ if( psEncC->sLP.transition_frame_no <= 0 ) {
+ encControl->switchReady = 1;
+ /* Make room for redundancy */
+ encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+ } else {
+ /* Direction: down (at double speed) */
+ psEncC->sLP.mode = -2;
+ }
+ }
+ }
+ else
+ /* Check if we should switch up */
+ if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz )
+ {
+ /* Switch up */
+ if( encControl->opusCanSwitch ) {
+ /* Switch to a higher sample frequency */
+ fs_kHz = orig_kHz == 8 ? 12 : 16;
+
+ /* New transition */
+ psEncC->sLP.transition_frame_no = 0;
+
+ /* Reset transition filter state */
+ silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+
+ /* Direction: up */
+ psEncC->sLP.mode = 1;
+ } else {
+ if( psEncC->sLP.mode == 0 ) {
+ encControl->switchReady = 1;
+ /* Make room for redundancy */
+ encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+ } else {
+ /* Direction: up */
+ psEncC->sLP.mode = 1;
+ }
+ }
+ } else {
+ if (psEncC->sLP.mode<0)
+ psEncC->sLP.mode = 1;
+ }
+ }
+ }
+
+ return fs_kHz;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#define silk_encoder_state_Fxx silk_encoder_state_FIX
+#else
+#include "main_FLP.h"
+#define silk_encoder_state_Fxx silk_encoder_state_FLP
+#endif
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+#include "pitch_est_defines.h"
+
+static opus_int silk_setup_resamplers(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz /* I */
+);
+
+static opus_int silk_setup_fs(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz, /* I */
+ opus_int PacketSize_ms /* I */
+);
+
+static opus_int silk_setup_complexity(
+ silk_encoder_state *psEncC, /* I/O */
+ opus_int Complexity /* I */
+);
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+ silk_encoder_state *psEncC, /* I/O */
+ const silk_EncControlStruct *encControl /* I */
+);
+
+
+/* Control encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+)
+{
+ opus_int fs_kHz, ret = 0;
+
+ psEnc->sCmn.useDTX = encControl->useDTX;
+ psEnc->sCmn.useCBR = encControl->useCBR;
+ psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate;
+ psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate;
+ psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate;
+ psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate;
+ psEnc->sCmn.useInBandFEC = encControl->useInBandFEC;
+ psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI;
+ psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal;
+ psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch;
+ psEnc->sCmn.channelNb = channelNb;
+
+ if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) {
+ if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) {
+ /* Change in API sampling rate in the middle of encoding a packet */
+ ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz );
+ }
+ return ret;
+ }
+
+ /* Beyond this point we know that there are no previously coded frames in the payload buffer */
+
+ /********************************************/
+ /* Determine internal sampling rate */
+ /********************************************/
+ fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl );
+ if( force_fs_kHz ) {
+ fs_kHz = force_fs_kHz;
+ }
+ /********************************************/
+ /* Prepare resampler and buffered data */
+ /********************************************/
+ ret += silk_setup_resamplers( psEnc, fs_kHz );
+
+ /********************************************/
+ /* Set internal sampling frequency */
+ /********************************************/
+ ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms );
+
+ /********************************************/
+ /* Set encoding complexity */
+ /********************************************/
+ ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity );
+
+ /********************************************/
+ /* Set packet loss rate measured by farend */
+ /********************************************/
+ psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage;
+
+ /********************************************/
+ /* Set LBRR usage */
+ /********************************************/
+ ret += silk_setup_LBRR( &psEnc->sCmn, encControl );
+
+ psEnc->sCmn.controlled_since_last_payload = 1;
+
+ return ret;
+}
+
+static opus_int silk_setup_resamplers(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ SAVE_STACK;
+
+ if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz )
+ {
+ if( psEnc->sCmn.fs_kHz == 0 ) {
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 );
+ } else {
+ VARDECL( opus_int16, x_buf_API_fs_Hz );
+ VARDECL( silk_resampler_state_struct, temp_resampler_state );
+#ifdef FIXED_POINT
+ opus_int16 *x_bufFIX = psEnc->x_buf;
+#else
+ VARDECL( opus_int16, x_bufFIX );
+ opus_int32 new_buf_samples;
+#endif
+ opus_int32 api_buf_samples;
+ opus_int32 old_buf_samples;
+ opus_int32 buf_length_ms;
+
+ buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS;
+ old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz;
+
+#ifndef FIXED_POINT
+ new_buf_samples = buf_length_ms * fs_kHz;
+ ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ),
+ opus_int16 );
+ silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples );
+#endif
+
+ /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */
+ ALLOC( temp_resampler_state, 1, silk_resampler_state_struct );
+ ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 );
+
+ /* Calculate number of samples to temporarily upsample */
+ api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 );
+
+ /* Temporary resampling of x_buf data to API_fs_Hz */
+ ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 );
+ ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples );
+
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 );
+
+ /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */
+ ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples );
+
+#ifndef FIXED_POINT
+ silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples);
+#endif
+ }
+ }
+
+ psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz;
+
+ RESTORE_STACK;
+ return ret;
+}
+
+static opus_int silk_setup_fs(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz, /* I */
+ opus_int PacketSize_ms /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ /* Set packet size */
+ if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) {
+ if( ( PacketSize_ms != 10 ) &&
+ ( PacketSize_ms != 20 ) &&
+ ( PacketSize_ms != 40 ) &&
+ ( PacketSize_ms != 60 ) ) {
+ ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if( PacketSize_ms <= 10 ) {
+ psEnc->sCmn.nFramesPerPacket = 1;
+ psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1;
+ psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz );
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ } else {
+ psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS );
+ psEnc->sCmn.nb_subfr = MAX_NB_SUBFR;
+ psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz );
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ }
+ }
+ psEnc->sCmn.PacketSize_ms = PacketSize_ms;
+ psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
+ }
+
+ /* Set internal sampling frequency */
+ celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+ celt_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 );
+ if( psEnc->sCmn.fs_kHz != fs_kHz ) {
+ /* reset part of the state */
+ silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) );
+ silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) );
+ silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+ silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) );
+ psEnc->sCmn.inputBufIx = 0;
+ psEnc->sCmn.nFramesEncoded = 0;
+ psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
+
+ /* Initialize non-zero parameters */
+ psEnc->sCmn.prevLag = 100;
+ psEnc->sCmn.first_frame_after_reset = 1;
+ psEnc->sShape.LastGainIndex = 10;
+ psEnc->sCmn.sNSQ.lagPrev = 100;
+ psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536;
+ psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+
+ psEnc->sCmn.fs_kHz = fs_kHz;
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else {
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ }
+ if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) {
+ psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER;
+ psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB;
+ } else {
+ psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER;
+ psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB;
+ }
+ psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz;
+ psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr );
+ psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+ psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz );
+ psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz );
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+ } else {
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+ }
+ if( psEnc->sCmn.fs_kHz == 16 ) {
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+ } else if( psEnc->sCmn.fs_kHz == 12 ) {
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+ } else {
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+ }
+ }
+
+ /* Check that settings are valid */
+ celt_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length );
+
+ return ret;
+}
+
+static opus_int silk_setup_complexity(
+ silk_encoder_state *psEncC, /* I/O */
+ opus_int Complexity /* I */
+)
+{
+ opus_int ret = 0;
+
+ /* Set encoding complexity */
+ celt_assert( Complexity >= 0 && Complexity <= 10 );
+ if( Complexity < 1 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 );
+ psEncC->pitchEstimationLPCOrder = 6;
+ psEncC->shapingLPCOrder = 12;
+ psEncC->la_shape = 3 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 1;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->NLSF_MSVQ_Survivors = 2;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 2 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 );
+ psEncC->pitchEstimationLPCOrder = 8;
+ psEncC->shapingLPCOrder = 14;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 1;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->NLSF_MSVQ_Survivors = 3;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 3 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 );
+ psEncC->pitchEstimationLPCOrder = 6;
+ psEncC->shapingLPCOrder = 12;
+ psEncC->la_shape = 3 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 2;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->NLSF_MSVQ_Survivors = 2;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 4 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 );
+ psEncC->pitchEstimationLPCOrder = 8;
+ psEncC->shapingLPCOrder = 14;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 2;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->NLSF_MSVQ_Survivors = 4;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 6 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 );
+ psEncC->pitchEstimationLPCOrder = 10;
+ psEncC->shapingLPCOrder = 16;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 2;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->NLSF_MSVQ_Survivors = 6;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ } else if( Complexity < 8 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 );
+ psEncC->pitchEstimationLPCOrder = 12;
+ psEncC->shapingLPCOrder = 20;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 3;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->NLSF_MSVQ_Survivors = 8;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ } else {
+ psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 );
+ psEncC->pitchEstimationLPCOrder = 16;
+ psEncC->shapingLPCOrder = 24;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->NLSF_MSVQ_Survivors = 16;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ }
+
+ /* Do not allow higher pitch estimation LPC order than predict LPC order */
+ psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder );
+ psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape;
+ psEncC->Complexity = Complexity;
+
+ celt_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER );
+ celt_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER );
+ celt_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES );
+ celt_assert( psEncC->warping_Q16 <= 32767 );
+ celt_assert( psEncC->la_shape <= LA_SHAPE_MAX );
+ celt_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX );
+
+ return ret;
+}
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+ silk_encoder_state *psEncC, /* I/O */
+ const silk_EncControlStruct *encControl /* I */
+)
+{
+ opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR;
+
+ LBRR_in_previous_packet = psEncC->LBRR_enabled;
+ psEncC->LBRR_enabled = encControl->LBRR_coded;
+ if( psEncC->LBRR_enabled ) {
+ /* Set gain increase for coding LBRR excitation */
+ if( LBRR_in_previous_packet == 0 ) {
+ /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
+ psEncC->LBRR_GainIncreases = 7;
+ } else {
+ psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.2, 16 ) ), 3 );
+ }
+ }
+
+ return ret;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "define.h"
+#include "API.h"
+#include "control.h"
+#include "typedef.h"
+#include "stack_alloc.h"
+#include "structs.h"
+#include "tuning_parameters.h"
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+
+#ifdef ENABLE_DRED
+#include "dred_encoder.h"
+#endif
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder( /* O Returns error code */
+ const void *encState, /* I State */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+);
+
+/****************************************/
+/* Encoder functions */
+/****************************************/
+
+opus_int silk_Get_Encoder_Size( /* O Returns error code */
+ opus_int *encSizeBytes, /* O Number of bytes in SILK encoder state */
+ opus_int channels /* I Number of channels */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ *encSizeBytes = sizeof( silk_encoder );
+ /* Skip second encoder state for mono. */
+ if ( channels == 1 ) {
+ *encSizeBytes -= sizeof( silk_encoder_state_Fxx );
+ }
+
+ return ret;
+}
+
+/*************************/
+/* Init or Reset encoder */
+/*************************/
+opus_int silk_InitEncoder( /* O Returns error code */
+ void *encState, /* I/O State */
+ int channels, /* I Number of channels */
+ int arch, /* I Run-time architecture */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+)
+{
+ silk_encoder *psEnc;
+ opus_int n, ret = SILK_NO_ERROR;
+
+ psEnc = (silk_encoder *)encState;
+
+ /* Reset encoder. Skip second encoder state for mono. */
+ silk_memset( psEnc, 0, sizeof( silk_encoder ) - (channels==1)*sizeof( silk_encoder_state_Fxx ) );
+ for( n = 0; n < channels; n++ ) {
+ if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) {
+ celt_assert( 0 );
+ }
+ }
+
+ psEnc->nChannelsAPI = 1;
+ psEnc->nChannelsInternal = 1;
+
+ /* Read control structure */
+ if( ret += silk_QueryEncoder( encState, encStatus ) ) {
+ celt_assert( 0 );
+ }
+
+ return ret;
+}
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder( /* O Returns error code */
+ const void *encState, /* I State */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ silk_encoder_state_Fxx *state_Fxx;
+ silk_encoder *psEnc = (silk_encoder *)encState;
+
+ state_Fxx = psEnc->state_Fxx;
+
+ encStatus->nChannelsAPI = psEnc->nChannelsAPI;
+ encStatus->nChannelsInternal = psEnc->nChannelsInternal;
+ encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz;
+ encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz;
+ encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz;
+ encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz;
+ encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms;
+ encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps;
+ encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc;
+ encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity;
+ encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC;
+ encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX;
+ encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR;
+ encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+ encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch;
+ encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+
+ return ret;
+}
+
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */
+/* encControl->payloadSize_ms is set to */
+opus_int silk_Encode( /* O Returns error code */
+ void *encState, /* I/O State */
+ silk_EncControlStruct *encControl, /* I Control status */
+ const opus_res *samplesIn, /* I Speech sample input vector */
+ opus_int nSamplesIn, /* I Number of samples in input vector */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
+ const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
+ opus_int activity /* I Decision of Opus voice activity detector */
+)
+{
+ opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
+ opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
+ opus_int nSamplesFromInput = 0, nSamplesFromInputMax;
+ opus_int speech_act_thr_for_switch_Q8;
+ opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum;
+ silk_encoder *psEnc = ( silk_encoder * )encState;
+ VARDECL( opus_int16, buf );
+ opus_int transition, curr_block, tot_blocks;
+ SAVE_STACK;
+
+ celt_assert( encControl->nChannelsAPI >= encControl->nChannelsInternal && encControl->nChannelsAPI >= psEnc->nChannelsInternal );
+ if (encControl->reducedDependency)
+ {
+ for( n = 0; n < encControl->nChannelsAPI; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.first_frame_after_reset = 1;
+ }
+ }
+ for( n = 0; n < encControl->nChannelsAPI; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.nFramesEncoded = 0;
+ }
+ /* Check values in encoder control structure */
+ if( ( ret = check_control_input( encControl ) ) != 0 ) {
+ celt_assert( 0 );
+ RESTORE_STACK;
+ return ret;
+ }
+
+ encControl->switchReady = 0;
+
+ if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) {
+ /* Mono -> Stereo transition: init state of second channel and stereo state */
+ ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch );
+ silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) );
+ silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) );
+ psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0;
+ psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1;
+ psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0;
+ psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1;
+ psEnc->sStereo.width_prev_Q14 = 0;
+ psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 );
+ if( psEnc->nChannelsAPI == 2 ) {
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) );
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) );
+ }
+ }
+
+ transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal);
+
+ psEnc->nChannelsAPI = encControl->nChannelsAPI;
+ psEnc->nChannelsInternal = encControl->nChannelsInternal;
+
+ nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate );
+ tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1;
+ curr_block = 0;
+ if( prefillFlag ) {
+ silk_LP_state save_LP;
+ /* Only accept input length of 10 ms */
+ if( nBlocksOf10ms != 1 ) {
+ celt_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ if ( prefillFlag == 2 ) {
+ save_LP = psEnc->state_Fxx[ 0 ].sCmn.sLP;
+ /* Save the sampling rate so the bandwidth switching code can keep handling transitions. */
+ save_LP.saved_fs_kHz = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
+ }
+ /* Reset Encoder */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch );
+ /* Restore the variable LP state. */
+ if ( prefillFlag == 2 ) {
+ psEnc->state_Fxx[ n ].sCmn.sLP = save_LP;
+ }
+ celt_assert( !ret );
+ }
+ tmp_payloadSize_ms = encControl->payloadSize_ms;
+ encControl->payloadSize_ms = 10;
+ tmp_complexity = encControl->complexity;
+ encControl->complexity = 0;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1;
+ }
+ } else {
+ /* Only accept input lengths that are a multiple of 10 ms */
+ if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) {
+ celt_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ /* Make sure no more than one packet can be produced */
+ if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) {
+ celt_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ }
+
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ /* Force the side channel to the same rate as the mid */
+ opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
+ if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return ret;
+ }
+ if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) {
+ for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+ psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0;
+ }
+ }
+ psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX;
+ }
+ celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+
+ /* Input buffering/resampling and encoding */
+ nSamplesToBufferMax =
+ 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
+ nSamplesFromInputMax =
+ silk_DIV32_16( nSamplesToBufferMax *
+ psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz,
+ psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+ ALLOC( buf, nSamplesFromInputMax, opus_int16 );
+ while( 1 ) {
+ int curr_nBitsUsedLBRR = 0;
+ nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx;
+ nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax );
+ nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+ /* Resample and write to buffer */
+ if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
+ opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[ n ] = RES2INT16(samplesIn[ 2 * n ]);
+ }
+ /* Making sure to start both resamplers from the same state when switching from mono to stereo */
+ if( psEnc->nPrevChannelsInternal == 1 && id==0 ) {
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state));
+ }
+
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+
+ nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx;
+ nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[ n ] = RES2INT16(samplesIn[ 2 * n + 1 ]);
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+
+ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer;
+ } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) {
+ /* Combine left and right channels before resampling */
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ sum = RES2INT16(samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]);
+ buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ /* On the first mono frame, average the results for the two resampler states */
+ if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) {
+ ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) {
+ psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] =
+ silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ]
+ + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1);
+ }
+ }
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+ } else {
+ celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 );
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[n] = RES2INT16(samplesIn[n]);
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+ }
+
+ samplesIn += nSamplesFromInput * encControl->nChannelsAPI;
+ nSamplesIn -= nSamplesFromInput;
+
+ /* Default */
+ psEnc->allowBandwidthSwitch = 0;
+
+ /* Silk encoder */
+ if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) {
+ /* Enough data in input buffer, so encode */
+ celt_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+ celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length );
+
+ /* Deal with LBRR data */
+ if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) {
+ /* Create space at start of payload for VAD and FEC flags */
+ opus_uint8 iCDF[ 2 ] = { 0, 0 };
+ iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+ ec_enc_icdf( psRangeEnc, 0, iCDF, 8 );
+ curr_nBitsUsedLBRR = ec_tell( psRangeEnc );
+
+ /* Encode any LBRR data from previous packet */
+ /* Encode LBRR flags */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ LBRR_symbol = 0;
+ for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+ LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i );
+ }
+ psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0;
+ if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) {
+ ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 );
+ }
+ }
+
+ /* Code LBRR indices and excitation signals */
+ for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) {
+ opus_int condCoding;
+
+ if( encControl->nChannelsInternal == 2 && n == 0 ) {
+ silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] );
+ /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
+ if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) {
+ silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] );
+ }
+ }
+ /* Use conditional coding if previous frame available */
+ if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) {
+ condCoding = CODE_CONDITIONALLY;
+ } else {
+ condCoding = CODE_INDEPENDENTLY;
+ }
+ silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding );
+ silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType,
+ psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length );
+ }
+ }
+ }
+
+ /* Reset LBRR flags */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) );
+ }
+ curr_nBitsUsedLBRR = ec_tell( psRangeEnc ) - curr_nBitsUsedLBRR;
+ }
+
+ silk_HP_variable_cutoff( psEnc->state_Fxx );
+
+ /* Total target bits for packet */
+ nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+ /* Subtract bits used for LBRR */
+ if( !prefillFlag ) {
+ /* psEnc->nBitsUsedLBRR is an exponential moving average of the LBRR usage,
+ except that for the first LBRR frame it does no averaging and for the first
+ frame after after LBRR, it goes back to zero immediately. */
+ if ( curr_nBitsUsedLBRR < 10 ) {
+ psEnc->nBitsUsedLBRR = 0;
+ } else if ( psEnc->nBitsUsedLBRR < 10) {
+ psEnc->nBitsUsedLBRR = curr_nBitsUsedLBRR;
+ } else {
+ psEnc->nBitsUsedLBRR = ( psEnc->nBitsUsedLBRR + curr_nBitsUsedLBRR ) / 2;
+ }
+ nBits -= psEnc->nBitsUsedLBRR;
+ }
+ /* Divide by number of uncoded frames left in packet */
+ nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket );
+ /* Convert to bits/second */
+ if( encControl->payloadSize_ms == 10 ) {
+ TargetRate_bps = silk_SMULBB( nBits, 100 );
+ } else {
+ TargetRate_bps = silk_SMULBB( nBits, 50 );
+ }
+ /* Subtract fraction of bits in excess of target in previous frames and packets */
+ TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+ if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) {
+ /* Compare actual vs target bits so far in this packet */
+ opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+ TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+ }
+ /* Never exceed input bitrate */
+ TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 );
+
+ /* Convert Left/Right to Mid/Side */
+ if( encControl->nChannelsInternal == 2 ) {
+ silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ],
+ psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ],
+ MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono,
+ psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+ if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+ /* Reset side channel encoder memory for first frame with side coding */
+ if( psEnc->prev_decode_only_middle == 1 ) {
+ silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) );
+ silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) );
+ psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100;
+ psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100;
+ psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10;
+ psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
+ psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
+ }
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity );
+ } else {
+ psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
+ }
+ if( !prefillFlag ) {
+ silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+ if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+ silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+ }
+ }
+ } else {
+ /* Buffering */
+ silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
+ }
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity );
+
+ /* Encode */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ opus_int maxBits, useCBR;
+
+ /* Handling rate constraints */
+ maxBits = encControl->maxBits;
+ if( tot_blocks == 2 && curr_block == 0 ) {
+ maxBits = maxBits * 3 / 5;
+ } else if( tot_blocks == 3 ) {
+ if( curr_block == 0 ) {
+ maxBits = maxBits * 2 / 5;
+ } else if( curr_block == 1 ) {
+ maxBits = maxBits * 3 / 4;
+ }
+ }
+ useCBR = encControl->useCBR && curr_block == tot_blocks - 1;
+
+ if( encControl->nChannelsInternal == 1 ) {
+ channelRate_bps = TargetRate_bps;
+ } else {
+ channelRate_bps = MStargetRates_bps[ n ];
+ if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) {
+ useCBR = 0;
+ /* Give mid up to 1/2 of the max bits for that frame */
+ maxBits -= encControl->maxBits / ( tot_blocks * 2 );
+ }
+ }
+
+ if( channelRate_bps > 0 ) {
+ opus_int condCoding;
+
+ silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps );
+
+ /* Use independent coding if no previous frame available */
+ if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) {
+ condCoding = CODE_INDEPENDENTLY;
+ } else if( n > 0 && psEnc->prev_decode_only_middle ) {
+ /* If we skipped a side frame in this packet, we don't
+ need LTP scaling; the LTP state is well-defined. */
+ condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+ } else {
+ condCoding = CODE_CONDITIONALLY;
+ }
+ if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) {
+ silk_assert( 0 );
+ }
+ }
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0;
+ psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++;
+ }
+ psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ];
+
+ /* Insert VAD and FEC flags at beginning of bitstream */
+ if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) {
+ flags = 0;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+ flags = silk_LSHIFT( flags, 1 );
+ flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ];
+ }
+ flags = silk_LSHIFT( flags, 1 );
+ flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag;
+ }
+ if( !prefillFlag ) {
+ ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+ }
+
+ /* Return zero bytes if all channels DTXed */
+ if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) {
+ *nBytesOut = 0;
+ }
+
+ psEnc->nBitsExceeded += *nBytesOut * 8;
+ psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+ psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 );
+
+ /* Update flag indicating if bandwidth switching is allowed */
+ speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ),
+ SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms );
+ if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) {
+ psEnc->allowBandwidthSwitch = 1;
+ psEnc->timeSinceSwitchAllowed_ms = 0;
+ } else {
+ psEnc->allowBandwidthSwitch = 0;
+ psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms;
+ }
+ }
+
+ if( nSamplesIn == 0 ) {
+ break;
+ }
+ } else {
+ break;
+ }
+ curr_block++;
+ }
+
+ psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
+
+ encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch;
+ encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+ encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+ encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14;
+ if( prefillFlag ) {
+ encControl->payloadSize_ms = tmp_payloadSize_ms;
+ encControl->complexity = tmp_complexity;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0;
+ }
+ }
+
+ encControl->signalType = psEnc->state_Fxx[0].sCmn.indices.signalType;
+ encControl->offset = silk_Quantization_Offsets_Q10
+ [ psEnc->state_Fxx[0].sCmn.indices.signalType >> 1 ]
+ [ psEnc->state_Fxx[0].sCmn.indices.quantOffsetType ];
+ RESTORE_STACK;
+ return ret;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Encode side-information parameters to payload */
+void silk_encode_indices(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, typeOffset;
+ opus_int encode_absolute_lagIndex, delta_lagIndex;
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ const SideInfoIndices *psIndices;
+
+ if( encode_LBRR ) {
+ psIndices = &psEncC->indices_LBRR[ FrameIndex ];
+ } else {
+ psIndices = &psEncC->indices;
+ }
+
+ /*******************************************/
+ /* Encode signal type and quantizer offset */
+ /*******************************************/
+ typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType;
+ celt_assert( typeOffset >= 0 && typeOffset < 6 );
+ celt_assert( encode_LBRR == 0 || typeOffset >= 2 );
+ if( encode_LBRR || typeOffset >= 2 ) {
+ ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 );
+ }
+
+ /****************/
+ /* Encode gains */
+ /****************/
+ /* first subframe */
+ if( condCoding == CODE_CONDITIONALLY ) {
+ /* conditional coding */
+ silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 );
+ } else {
+ /* independent coding, in two stages: MSB bits followed by 3 LSBs */
+ silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN );
+ ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 );
+ }
+
+ /* remaining subframes */
+ for( i = 1; i < psEncC->nb_subfr; i++ ) {
+ silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 );
+ }
+
+ /****************/
+ /* Encode NLSFs */
+ /****************/
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 );
+ silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] );
+ celt_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder );
+ for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) {
+ if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) {
+ ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+ } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+ ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ }
+ }
+
+ /* Encode NLSF interpolation factor */
+ if( psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 );
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 );
+ }
+
+ if( psIndices->signalType == TYPE_VOICED )
+ {
+ /*********************/
+ /* Encode pitch lags */
+ /*********************/
+ /* lag index */
+ encode_absolute_lagIndex = 1;
+ if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) {
+ /* Delta Encoding */
+ delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex;
+ if( delta_lagIndex < -8 || delta_lagIndex > 11 ) {
+ delta_lagIndex = 0;
+ } else {
+ delta_lagIndex = delta_lagIndex + 9;
+ encode_absolute_lagIndex = 0; /* Only use delta */
+ }
+ silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 );
+ ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 );
+ }
+ if( encode_absolute_lagIndex ) {
+ /* Absolute encoding */
+ opus_int32 pitch_high_bits, pitch_low_bits;
+ pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+ pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+ silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 );
+ silk_assert( pitch_high_bits < 32 );
+ ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 );
+ ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 );
+ }
+ psEncC->ec_prevLagIndex = psIndices->lagIndex;
+
+ /* Contour index */
+ silk_assert( psIndices->contourIndex >= 0 );
+ silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) ||
+ ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) ||
+ ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) ||
+ ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) );
+ ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 );
+
+ /********************/
+ /* Encode LTP gains */
+ /********************/
+ /* PERIndex value */
+ silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 );
+ ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 );
+
+ /* Codebook Indices */
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) );
+ ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 );
+ }
+
+ /**********************/
+ /* Encode LTP scaling */
+ /**********************/
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 );
+ ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 );
+ }
+ silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 );
+ }
+
+ psEncC->ec_prevSignalType = psIndices->signalType;
+
+ /***************/
+ /* Encode seed */
+ /***************/
+ silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 );
+ ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 );
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/*********************************************/
+/* Encode quantization indices of excitation */
+/*********************************************/
+
+static OPUS_INLINE opus_int combine_and_check( /* return ok */
+ opus_int *pulses_comb, /* O */
+ const opus_int *pulses_in, /* I */
+ opus_int max_pulses, /* I max value for sum of pulses */
+ opus_int len /* I number of output values */
+)
+{
+ opus_int k, sum;
+
+ for( k = 0; k < len; k++ ) {
+ sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ];
+ if( sum > max_pulses ) {
+ return 1;
+ }
+ pulses_comb[ k ] = sum;
+ }
+
+ return 0;
+}
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ opus_int8 pulses[], /* I quantization indices */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
+ opus_int32 abs_q, minSumBits_Q5, sumBits_Q5;
+ VARDECL( opus_int, abs_pulses );
+ VARDECL( opus_int, sum_pulses );
+ VARDECL( opus_int, nRshifts );
+ opus_int pulses_comb[ 8 ];
+ opus_int *abs_pulses_ptr;
+ const opus_int8 *pulses_ptr;
+ const opus_uint8 *cdf_ptr;
+ const opus_uint8 *nBits_ptr;
+ SAVE_STACK;
+
+ silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/
+
+ /****************************/
+ /* Prepare for shell coding */
+ /****************************/
+ /* Calculate number of shell blocks */
+ silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+ iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+ celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+ iter++;
+ silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8));
+ }
+
+ /* Take the absolute value of the pulses */
+ ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int );
+ silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) );
+ for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) {
+ abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] );
+ abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] );
+ abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] );
+ abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] );
+ }
+
+ /* Calc sum pulses per shell code frame */
+ ALLOC( sum_pulses, iter, opus_int );
+ ALLOC( nRshifts, iter, opus_int );
+ abs_pulses_ptr = abs_pulses;
+ for( i = 0; i < iter; i++ ) {
+ nRshifts[ i ] = 0;
+
+ while( 1 ) {
+ /* 1+1 -> 2 */
+ scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 );
+ /* 2+2 -> 4 */
+ scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 );
+ /* 4+4 -> 8 */
+ scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 );
+ /* 8+8 -> 16 */
+ scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 );
+
+ if( scale_down ) {
+ /* We need to downscale the quantization signal */
+ nRshifts[ i ]++;
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 );
+ }
+ } else {
+ /* Jump out of while(1) loop and go to next shell coding frame */
+ break;
+ }
+ }
+ abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+
+ /**************/
+ /* Rate level */
+ /**************/
+ /* find rate level that leads to fewest bits for coding of pulses per block info */
+ minSumBits_Q5 = silk_int32_MAX;
+ for( k = 0; k < N_RATE_LEVELS - 1; k++ ) {
+ nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ];
+ sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ];
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] > 0 ) {
+ sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ];
+ } else {
+ sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ];
+ }
+ }
+ if( sumBits_Q5 < minSumBits_Q5 ) {
+ minSumBits_Q5 = sumBits_Q5;
+ RateLevelIndex = k;
+ }
+ }
+ ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+ /***************************************************/
+ /* Sum-Weighted-Pulses Encoding */
+ /***************************************************/
+ cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] == 0 ) {
+ ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 );
+ for( k = 0; k < nRshifts[ i ] - 1; k++ ) {
+ ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+ }
+ ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+ }
+ }
+
+ /******************/
+ /* Shell Encoding */
+ /******************/
+ for( i = 0; i < iter; i++ ) {
+ if( sum_pulses[ i ] > 0 ) {
+ silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] );
+ }
+ }
+
+ /****************/
+ /* LSB Encoding */
+ /****************/
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] > 0 ) {
+ pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ];
+ nLS = nRshifts[ i ] - 1;
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] );
+ for( j = nLS; j > 0; j-- ) {
+ bit = silk_RSHIFT( abs_q, j ) & 1;
+ ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+ }
+ bit = abs_q & 1;
+ ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+ }
+ }
+ }
+
+ /****************/
+ /* Encode signs */
+ /****************/
+ silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+void silk_LTP_analysis_filter_FIX(
+ opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
+ const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
+ const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
+)
+{
+ const opus_int16 *x_ptr, *x_lag_ptr;
+ opus_int16 Btmp_Q14[ LTP_ORDER ];
+ opus_int16 *LTP_res_ptr;
+ opus_int k, i;
+ opus_int32 LTP_est;
+
+ x_ptr = x;
+ LTP_res_ptr = LTP_res;
+ for( k = 0; k < nb_subfr; k++ ) {
+
+ x_lag_ptr = x_ptr - pitchL[ k ];
+
+ Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ];
+ Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ];
+ Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ];
+ Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ];
+ Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ];
+
+ /* LTP analysis FIR filter */
+ for( i = 0; i < subfr_length + pre_length; i++ ) {
+ LTP_res_ptr[ i ] = x_ptr[ i ];
+
+ /* Long-term prediction */
+ LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] );
+ LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] );
+ LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] );
+ LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] );
+ LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] );
+
+ LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/
+
+ /* Subtract long-term prediction */
+ LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est );
+
+ /* Scale residual */
+ LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] );
+
+ x_lag_ptr++;
+ }
+
+ /* Update pointers */
+ LTP_res_ptr += subfr_length + pre_length;
+ x_ptr += subfr_length;
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int round_loss;
+
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ /* Only scale if first frame in packet */
+ round_loss = psEnc->sCmn.PacketLoss_perc * psEnc->sCmn.nFramesPerPacket;
+ if ( psEnc->sCmn.LBRR_flag ) {
+ /* LBRR reduces the effective loss. In practice, it does not square the loss because
+ losses aren't independent, but that still seems to work best. We also never go below 2%. */
+ round_loss = 2 + silk_SMULBB( round_loss, round_loss ) / 100;
+ }
+ psEnc->sCmn.indices.LTP_scaleIndex = silk_SMULBB( psEncCtrl->LTPredCodGain_Q7, round_loss ) > silk_log2lin( 128*7 + 2900-psEnc->sCmn.SNR_dB_Q7 );
+ psEnc->sCmn.indices.LTP_scaleIndex += silk_SMULBB( psEncCtrl->LTPredCodGain_Q7, round_loss ) > silk_log2lin( 128*7 + 3900-psEnc->sCmn.SNR_dB_Q7 );
+ } else {
+ /* Default is minimum scaling */
+ psEnc->sCmn.indices.LTP_scaleIndex = 0;
+ }
+ psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ];
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+/* Every other sample is linearly interpolated, for speed. */
+/* Window length must be between 16 and 120 (incl) and a multiple of 4. */
+
+/* Matlab code for table:
+ for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
+*/
+static const opus_int16 freq_table_Q16[ 27 ] = {
+ 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202,
+ 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422,
+ 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702,
+};
+
+void silk_apply_sine_window(
+ opus_int16 px_win[], /* O Pointer to windowed signal */
+ const opus_int16 px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+)
+{
+ opus_int k, f_Q16, c_Q16;
+ opus_int32 S0_Q16, S1_Q16;
+
+ celt_assert( win_type == 1 || win_type == 2 );
+
+ /* Length must be in a range from 16 to 120 and a multiple of 4 */
+ celt_assert( length >= 16 && length <= 120 );
+ celt_assert( ( length & 3 ) == 0 );
+
+ /* Frequency */
+ k = ( length >> 2 ) - 4;
+ celt_assert( k >= 0 && k <= 26 );
+ f_Q16 = (opus_int)freq_table_Q16[ k ];
+
+ /* Factor used for cosine approximation */
+ c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 );
+ silk_assert( c_Q16 >= -32768 );
+
+ /* initialize state */
+ if( win_type == 1 ) {
+ /* start from 0 */
+ S0_Q16 = 0;
+ /* approximation of sin(f) */
+ S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 );
+ } else {
+ /* start from 1 */
+ S0_Q16 = ( (opus_int32)1 << 16 );
+ /* approximation of cos(f) */
+ S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 );
+ }
+
+ /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
+ /* 4 samples at a time */
+ for( k = 0; k < length; k += 4 ) {
+ px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] );
+ px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] );
+ S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1;
+ S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) );
+
+ px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] );
+ px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] );
+ S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16;
+ S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) );
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "celt_lpc.h"
+
+/* Compute autocorrelation */
+void silk_autocorr(
+ opus_int32 *results, /* O Result (length correlationCount) */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *inputData, /* I Input data to correlate */
+ const opus_int inputDataSize, /* I Length of input */
+ const opus_int correlationCount, /* I Number of correlation taps to compute */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int corrCount;
+ corrCount = silk_min_int( inputDataSize, correlationCount );
+ *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch);
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "define.h"
+#include "tuning_parameters.h"
+#include "pitch.h"
+
+#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+
+#define QA 25
+#define N_BITS_HEAD_ROOM 3
+#define MIN_RSHIFTS -16
+#define MAX_RSHIFTS (32 - QA)
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified_c(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int k, n, s, lz, rshifts, reached_max_gain;
+ opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
+ const opus_int16 *x_ptr;
+ opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
+ opus_int64 C0_64;
+
+ celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+ /* Compute autocorrelations, added over subframes */
+ C0_64 = silk_inner_prod16( x, x, subfr_length*nb_subfr, arch );
+ lz = silk_CLZ64(C0_64);
+ rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
+ if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
+ if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
+
+ if (rshifts > 0) {
+ C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts );
+ } else {
+ C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts );
+ }
+
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
+ silk_inner_prod16( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts );
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ int i;
+ opus_int32 d;
+ x_ptr = x + s * subfr_length;
+ celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
+ for( n = 1; n < D + 1; n++ ) {
+ for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
+ d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
+ xcorr[ n - 1 ] += d;
+ }
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
+ }
+ }
+ }
+ silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+
+ /* Initialize */
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+
+ invGain_Q30 = (opus_int32)1 << 30;
+ reached_max_gain = 0;
+ for( n = 0; n < D; n++ ) {
+ /* Update first row of correlation matrix (without first element) */
+ /* Update last row of correlation matrix (without last element, stored in reversed order) */
+ /* Update C * Af */
+ /* Update C * flipud(Af) (stored in reversed order) */
+ if( rshifts > -2 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp_QA = Af_QA[ k ];
+ tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */
+ tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */
+ }
+ tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */
+ /* We sometimes get overflows in the multiplications (even beyond +/- 2^32),
+ but they cancel each other and the real result seems to always fit in a 32-bit
+ signed integer. This was determined experimentally, not theoretically (unfortunately). */
+ tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */
+ tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */
+ }
+ tmp1 = -tmp1; /* Q17 */
+ tmp2 = -tmp2; /* Q17 */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
+ silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
+ silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ }
+ }
+ }
+
+ /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+ tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */
+ tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */
+ num = 0; /* Q( -rshifts ) */
+ nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */
+ for( k = 0; k < n; k++ ) {
+ Atmp_QA = Af_QA[ k ];
+ lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
+ lz = silk_min( 32 - QA, lz );
+ Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */
+
+ tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
+ Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */
+ }
+ CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */
+ CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */
+ num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */
+ num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */
+
+ /* Calculate the next order reflection (parcor) coefficient */
+ if( silk_abs( num ) < nrg ) {
+ rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
+ } else {
+ rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
+ }
+
+ /* Update inverse prediction gain */
+ tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+ tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
+ if( tmp1 <= minInvGain_Q30 ) {
+ /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+ tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */
+ rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */
+ if( rc_Q31 > 0 ) {
+ /* Newton-Raphson iteration */
+ rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */
+ rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */
+ if( num < 0 ) {
+ /* Ensure adjusted reflection coefficients has the original sign */
+ rc_Q31 = -rc_Q31;
+ }
+ }
+ invGain_Q30 = minInvGain_Q30;
+ reached_max_gain = 1;
+ } else {
+ invGain_Q30 = tmp1;
+ }
+
+ /* Update the AR coefficients */
+ for( k = 0; k < (n + 1) >> 1; k++ ) {
+ tmp1 = Af_QA[ k ]; /* QA */
+ tmp2 = Af_QA[ n - k - 1 ]; /* QA */
+ Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */
+ Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */
+ }
+ Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */
+
+ if( reached_max_gain ) {
+ /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+ for( k = n + 1; k < D; k++ ) {
+ Af_QA[ k ] = 0;
+ }
+ break;
+ }
+
+ /* Update C * Af and C * Ab */
+ for( k = 0; k <= n + 1; k++ ) {
+ tmp1 = CAf[ k ]; /* Q( -rshifts ) */
+ tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */
+ CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ }
+ }
+
+ if( reached_max_gain ) {
+ for( k = 0; k < D; k++ ) {
+ /* Scale coefficients */
+ A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
+ }
+ /* Subtract energy of preceding samples from C0 */
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16( x_ptr, x_ptr, D, arch ), rshifts );
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts);
+ }
+ }
+ /* Approximate residual energy */
+ *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
+ *res_nrg_Q = -rshifts;
+ } else {
+ /* Return residual energy */
+ nrg = CAf[ 0 ]; /* Q( -rshifts ) */
+ tmp1 = (opus_int32)1 << 16; /* Q16 */
+ for( k = 0; k < D; k++ ) {
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */
+ nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */
+ tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */
+ A_Q16[ k ] = -Atmp1;
+ }
+ *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
+ *res_nrg_Q = -rshifts;
+ }
+}
--- /dev/null
+/* Copyright (c) 2014-2020, Cisco Systems, INC
+ Written by XiangMingZhu WeiZhou MinPeng YanWang FrancisQuiers
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must 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 "SigProc_FIX.h"
+#include "define.h"
+#include "tuning_parameters.h"
+#include "pitch.h"
+#include "celt/x86/x86cpu.h"
+
+#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+
+#define QA 25
+#define N_BITS_HEAD_ROOM 3
+#define MIN_RSHIFTS -16
+#define MAX_RSHIFTS (32 - QA)
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified_sse4_1(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int k, n, s, lz, rshifts, reached_max_gain;
+ opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
+ const opus_int16 *x_ptr;
+ opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
+ opus_int64 C0_64;
+
+ __m128i FIRST_3210, LAST_3210, ATMP_3210, TMP1_3210, TMP2_3210, T1_3210, T2_3210, PTR_3210, SUBFR_3210, X1_3210, X2_3210;
+ __m128i CONST1 = _mm_set1_epi32(1);
+
+ celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+ /* Compute autocorrelations, added over subframes */
+ C0_64 = silk_inner_prod16( x, x, subfr_length*nb_subfr, arch );
+ lz = silk_CLZ64(C0_64);
+ rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz;
+ if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS;
+ if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS;
+
+ if (rshifts > 0) {
+ C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts );
+ } else {
+ C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts );
+ }
+
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
+ silk_inner_prod16( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts );
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ int i;
+ opus_int32 d;
+ x_ptr = x + s * subfr_length;
+ celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
+ for( n = 1; n < D + 1; n++ ) {
+ for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
+ d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
+ xcorr[ n - 1 ] += d;
+ }
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
+ }
+ }
+ }
+ silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+
+ /* Initialize */
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+
+ invGain_Q30 = (opus_int32)1 << 30;
+ reached_max_gain = 0;
+ for( n = 0; n < D; n++ ) {
+ /* Update first row of correlation matrix (without first element) */
+ /* Update last row of correlation matrix (without last element, stored in reversed order) */
+ /* Update C * Af */
+ /* Update C * flipud(Af) (stored in reversed order) */
+ if( rshifts > -2 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp_QA = Af_QA[ k ];
+ tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */
+ tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */
+ }
+ tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */
+
+ X1_3210 = _mm_set1_epi32( x1 );
+ X2_3210 = _mm_set1_epi32( x2 );
+ TMP1_3210 = _mm_setzero_si128();
+ TMP2_3210 = _mm_setzero_si128();
+ for( k = 0; k < n - 3; k += 4 ) {
+ PTR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 1 - 3 ] );
+ SUBFR_3210 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k ] );
+ FIRST_3210 = _mm_loadu_si128( (__m128i *)(void*)&C_first_row[ k ] );
+ PTR_3210 = _mm_shuffle_epi32( PTR_3210, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+ LAST_3210 = _mm_loadu_si128( (__m128i *)(void*)&C_last_row[ k ] );
+ ATMP_3210 = _mm_loadu_si128( (__m128i *)(void*)&Af_QA[ k ] );
+
+ T1_3210 = _mm_mullo_epi32( PTR_3210, X1_3210 );
+ T2_3210 = _mm_mullo_epi32( SUBFR_3210, X2_3210 );
+
+ ATMP_3210 = _mm_srai_epi32( ATMP_3210, 7 );
+ ATMP_3210 = _mm_add_epi32( ATMP_3210, CONST1 );
+ ATMP_3210 = _mm_srai_epi32( ATMP_3210, 1 );
+
+ FIRST_3210 = _mm_add_epi32( FIRST_3210, T1_3210 );
+ LAST_3210 = _mm_add_epi32( LAST_3210, T2_3210 );
+
+ PTR_3210 = _mm_mullo_epi32( ATMP_3210, PTR_3210 );
+ SUBFR_3210 = _mm_mullo_epi32( ATMP_3210, SUBFR_3210 );
+
+ _mm_storeu_si128( (__m128i *)(void*)&C_first_row[ k ], FIRST_3210 );
+ _mm_storeu_si128( (__m128i *)(void*)&C_last_row[ k ], LAST_3210 );
+
+ TMP1_3210 = _mm_add_epi32( TMP1_3210, PTR_3210 );
+ TMP2_3210 = _mm_add_epi32( TMP2_3210, SUBFR_3210 );
+ }
+
+ TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_unpackhi_epi64(TMP1_3210, TMP1_3210 ) );
+ TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_unpackhi_epi64(TMP2_3210, TMP2_3210 ) );
+ TMP1_3210 = _mm_add_epi32( TMP1_3210, _mm_shufflelo_epi16(TMP1_3210, 0x0E ) );
+ TMP2_3210 = _mm_add_epi32( TMP2_3210, _mm_shufflelo_epi16(TMP2_3210, 0x0E ) );
+
+ tmp1 += _mm_cvtsi128_si32( TMP1_3210 );
+ tmp2 += _mm_cvtsi128_si32( TMP2_3210 );
+
+ for( ; k < n; k++ ) {
+ C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */
+ /* We sometimes get overflows in the multiplications (even beyond +/- 2^32),
+ but they cancel each other and the real result seems to always fit in a 32-bit
+ signed integer. This was determined experimentally, not theoretically (unfortunately). */
+ tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */
+ tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */
+ }
+
+ tmp1 = -tmp1; /* Q17 */
+ tmp2 = -tmp2; /* Q17 */
+
+ {
+ __m128i xmm_tmp1, xmm_tmp2;
+ __m128i xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1;
+ __m128i xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1;
+
+ xmm_tmp1 = _mm_set1_epi32( tmp1 );
+ xmm_tmp2 = _mm_set1_epi32( tmp2 );
+
+ for( k = 0; k <= n - 3; k += 4 ) {
+ xmm_x_ptr_n_k_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ n - k - 3 ] );
+ xmm_x_ptr_sub_x2x0 = OP_CVTEPI16_EPI32_M64( &x_ptr[ subfr_length - n + k - 1 ] );
+
+ xmm_x_ptr_n_k_x2x0 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 1, 2, 3 ) );
+
+ xmm_x_ptr_n_k_x2x0 = _mm_slli_epi32( xmm_x_ptr_n_k_x2x0, -rshifts - 1 );
+ xmm_x_ptr_sub_x2x0 = _mm_slli_epi32( xmm_x_ptr_sub_x2x0, -rshifts - 1 );
+
+ /* equal shift right 4 bytes, xmm_x_ptr_n_k_x3x1 = _mm_srli_si128(xmm_x_ptr_n_k_x2x0, 4)*/
+ xmm_x_ptr_n_k_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_n_k_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+ xmm_x_ptr_sub_x3x1 = _mm_shuffle_epi32( xmm_x_ptr_sub_x2x0, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+
+ xmm_x_ptr_n_k_x2x0 = _mm_mul_epi32( xmm_x_ptr_n_k_x2x0, xmm_tmp1 );
+ xmm_x_ptr_n_k_x3x1 = _mm_mul_epi32( xmm_x_ptr_n_k_x3x1, xmm_tmp1 );
+ xmm_x_ptr_sub_x2x0 = _mm_mul_epi32( xmm_x_ptr_sub_x2x0, xmm_tmp2 );
+ xmm_x_ptr_sub_x3x1 = _mm_mul_epi32( xmm_x_ptr_sub_x3x1, xmm_tmp2 );
+
+ xmm_x_ptr_n_k_x2x0 = _mm_srli_epi64( xmm_x_ptr_n_k_x2x0, 16 );
+ xmm_x_ptr_n_k_x3x1 = _mm_slli_epi64( xmm_x_ptr_n_k_x3x1, 16 );
+ xmm_x_ptr_sub_x2x0 = _mm_srli_epi64( xmm_x_ptr_sub_x2x0, 16 );
+ xmm_x_ptr_sub_x3x1 = _mm_slli_epi64( xmm_x_ptr_sub_x3x1, 16 );
+
+ xmm_x_ptr_n_k_x2x0 = _mm_blend_epi16( xmm_x_ptr_n_k_x2x0, xmm_x_ptr_n_k_x3x1, 0xCC );
+ xmm_x_ptr_sub_x2x0 = _mm_blend_epi16( xmm_x_ptr_sub_x2x0, xmm_x_ptr_sub_x3x1, 0xCC );
+
+ X1_3210 = _mm_loadu_si128( (__m128i *)(void*)&CAf[ k ] );
+ PTR_3210 = _mm_loadu_si128( (__m128i *)(void*)&CAb[ k ] );
+
+ X1_3210 = _mm_add_epi32( X1_3210, xmm_x_ptr_n_k_x2x0 );
+ PTR_3210 = _mm_add_epi32( PTR_3210, xmm_x_ptr_sub_x2x0 );
+
+ _mm_storeu_si128( (__m128i *)(void*)&CAf[ k ], X1_3210 );
+ _mm_storeu_si128( (__m128i *)(void*)&CAb[ k ], PTR_3210 );
+ }
+
+ for( ; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
+ silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
+ silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ }
+ }
+ }
+ }
+
+ /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+ tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */
+ tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */
+ num = 0; /* Q( -rshifts ) */
+ nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */
+ for( k = 0; k < n; k++ ) {
+ Atmp_QA = Af_QA[ k ];
+ lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
+ lz = silk_min( 32 - QA, lz );
+ Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */
+
+ tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
+ Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */
+ }
+ CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */
+ CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */
+ num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */
+ num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */
+
+ /* Calculate the next order reflection (parcor) coefficient */
+ if( silk_abs( num ) < nrg ) {
+ rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
+ } else {
+ rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
+ }
+
+ /* Update inverse prediction gain */
+ tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+ tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
+ if( tmp1 <= minInvGain_Q30 ) {
+ /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+ tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */
+ rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */
+ if( rc_Q31 > 0 ) {
+ /* Newton-Raphson iteration */
+ rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */
+ rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */
+ if( num < 0 ) {
+ /* Ensure adjusted reflection coefficients has the original sign */
+ rc_Q31 = -rc_Q31;
+ }
+ }
+ invGain_Q30 = minInvGain_Q30;
+ reached_max_gain = 1;
+ } else {
+ invGain_Q30 = tmp1;
+ }
+
+ /* Update the AR coefficients */
+ for( k = 0; k < (n + 1) >> 1; k++ ) {
+ tmp1 = Af_QA[ k ]; /* QA */
+ tmp2 = Af_QA[ n - k - 1 ]; /* QA */
+ Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */
+ Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */
+ }
+ Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */
+
+ if( reached_max_gain ) {
+ /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+ for( k = n + 1; k < D; k++ ) {
+ Af_QA[ k ] = 0;
+ }
+ break;
+ }
+
+ /* Update C * Af and C * Ab */
+ for( k = 0; k <= n + 1; k++ ) {
+ tmp1 = CAf[ k ]; /* Q( -rshifts ) */
+ tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */
+ CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ }
+ }
+
+ if( reached_max_gain ) {
+ for( k = 0; k < D; k++ ) {
+ /* Scale coefficients */
+ A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
+ }
+ /* Subtract energy of preceding samples from C0 */
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16( x_ptr, x_ptr, D, arch ), rshifts );
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch ), -rshifts );
+ }
+ }
+ /* Approximate residual energy */
+ *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
+ *res_nrg_Q = -rshifts;
+ } else {
+ /* Return residual energy */
+ nrg = CAf[ 0 ]; /* Q( -rshifts ) */
+ tmp1 = (opus_int32)1 << 16; /* Q16 */
+ for( k = 0; k < D; k++ ) {
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */
+ nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */
+ tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */
+ A_Q16[ k ] = -Atmp1;
+ }
+ *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
+ *res_nrg_Q = -rshifts;
+ }
+
+#ifdef OPUS_CHECK_ASM
+ {
+ opus_int32 res_nrg_c = 0;
+ opus_int res_nrg_Q_c = 0;
+ opus_int32 A_Q16_c[ MAX_LPC_ORDER ] = {0};
+
+ silk_burg_modified_c(
+ &res_nrg_c,
+ &res_nrg_Q_c,
+ A_Q16_c,
+ x,
+ minInvGain_Q30,
+ subfr_length,
+ nb_subfr,
+ D,
+ 0
+ );
+
+ silk_assert( *res_nrg == res_nrg_c );
+ silk_assert( *res_nrg_Q == res_nrg_Q_c );
+ silk_assert( !memcmp( A_Q16, A_Q16_c, D * sizeof( *A_Q16 ) ) );
+ }
+#endif
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/**********************************************************************
+ * Correlation Matrix Computations for LS estimate.
+ **********************************************************************/
+
+#include "main_FIX.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int16 *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
+ const opus_int rshifts, /* I Right shifts of correlations */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int lag, i;
+ const opus_int16 *ptr1, *ptr2;
+ opus_int32 inner_prod;
+
+ ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
+ ptr2 = t;
+ /* Calculate X'*t */
+ if( rshifts > 0 ) {
+ /* Right shifting used */
+ for( lag = 0; lag < order; lag++ ) {
+ inner_prod = 0;
+ for( i = 0; i < L; i++ ) {
+ inner_prod = silk_ADD_RSHIFT32( inner_prod, silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts );
+ }
+ Xt[ lag ] = inner_prod; /* X[:,lag]'*t */
+ ptr1--; /* Go to next column of X */
+ }
+ } else {
+ silk_assert( rshifts == 0 );
+ for( lag = 0; lag < order; lag++ ) {
+ Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */
+ ptr1--; /* Go to next column of X */
+ }
+ }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
+ opus_int32 *nrg, /* O Energy of x vector */
+ opus_int *rshifts, /* O Right shifts of correlations and energy */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, j, lag;
+ opus_int32 energy;
+ const opus_int16 *ptr1, *ptr2;
+
+ /* Calculate energy to find shift used to fit in 32 bits */
+ silk_sum_sqr_shift( nrg, rshifts, x, L + order - 1 );
+ energy = *nrg;
+
+ /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
+ /* Remove contribution of first order - 1 samples */
+ for( i = 0; i < order - 1; i++ ) {
+ energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), *rshifts );
+ }
+
+ /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
+ /* Fill out the diagonal of the correlation matrix */
+ matrix_ptr( XX, 0, 0, order ) = energy;
+ silk_assert( energy >= 0 );
+ ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */
+ for( j = 1; j < order; j++ ) {
+ energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), *rshifts ) );
+ energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), *rshifts ) );
+ matrix_ptr( XX, j, j, order ) = energy;
+ silk_assert( energy >= 0 );
+ }
+
+ ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */
+ /* Calculate the remaining elements of the correlation matrix */
+ if( *rshifts > 0 ) {
+ /* Right shifting used */
+ for( lag = 1; lag < order; lag++ ) {
+ /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+ energy = 0;
+ for( i = 0; i < L; i++ ) {
+ energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), *rshifts );
+ }
+ /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+ matrix_ptr( XX, lag, 0, order ) = energy;
+ matrix_ptr( XX, 0, lag, order ) = energy;
+ for( j = 1; j < ( order - lag ); j++ ) {
+ energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), *rshifts ) );
+ energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), *rshifts ) );
+ matrix_ptr( XX, lag + j, j, order ) = energy;
+ matrix_ptr( XX, j, lag + j, order ) = energy;
+ }
+ ptr2--; /* Update pointer to first sample of next column (lag) in X */
+ }
+ } else {
+ for( lag = 1; lag < order; lag++ ) {
+ /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+ energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch );
+ matrix_ptr( XX, lag, 0, order ) = energy;
+ matrix_ptr( XX, 0, lag, order ) = energy;
+ /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+ for( j = 1; j < ( order - lag ); j++ ) {
+ energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) );
+ energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] );
+ matrix_ptr( XX, lag + j, j, order ) = energy;
+ matrix_ptr( XX, j, lag + j, order ) = energy;
+ }
+ ptr2--;/* Update pointer to first sample of next column (lag) in X */
+ }
+ }
+}
--- /dev/null
+/***********************************************************************
+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 <stdlib.h>
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ const opus_int16 x16[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+);
+
+void silk_encode_do_VAD_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int activity /* I Decision of Opus voice activity detector */
+)
+{
+ const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 );
+
+ /****************************/
+ /* Voice Activity Detection */
+ /****************************/
+ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
+ /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */
+ if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) {
+ psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1;
+ }
+
+ /**************************************************/
+ /* Convert speech activity into VAD and DTX flags */
+ /**************************************************/
+ if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) {
+ psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->sCmn.noSpeechCounter++;
+ if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.inDTX = 0;
+ } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+ psEnc->sCmn.inDTX = 0;
+ }
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+ } else {
+ psEnc->sCmn.noSpeechCounter = 0;
+ psEnc->sCmn.inDTX = 0;
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+ }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+)
+{
+ silk_encoder_control_FIX sEncCtrl;
+ opus_int i, iter, maxIter, found_upper, found_lower, ret = 0;
+ opus_int16 *x_frame;
+ ec_enc sRangeEnc_copy, sRangeEnc_copy2;
+ VARDECL(silk_nsq_state, sNSQ_copy);
+ opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+ opus_int32 gainsID, gainsID_lower, gainsID_upper;
+ opus_int16 gainMult_Q8;
+ opus_int16 ec_prevLagIndex_copy;
+ opus_int ec_prevSignalType_copy;
+ opus_int8 LastGainIndex_copy2;
+ opus_int gain_lock[ MAX_NB_SUBFR ] = {0};
+ opus_int16 best_gain_mult[ MAX_NB_SUBFR ];
+ opus_int best_sum[ MAX_NB_SUBFR ];
+ opus_int bits_margin;
+ SAVE_STACK;
+
+ /* Using ALLOC() instead of a regular stack allocation to minimize real stack use when using the pseudostack.
+ This is useful on some embedded systems. */
+ ALLOC(sNSQ_copy, 2, silk_nsq_state);
+
+ /* For CBR, 5 bits below budget is close enough. For VBR, allow up to 25% below the cap if we initially busted the budget. */
+ bits_margin = useCBR ? 5 : maxBits/4;
+ /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+ psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+ /**************************************************************/
+ /* Set up Input Pointers, and insert frame in input buffer */
+ /*************************************************************/
+ /* start of frame to encode */
+ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;
+
+ /***************************************/
+ /* Ensure smooth bandwidth transitions */
+ /***************************************/
+ silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /*******************************************/
+ /* Copy new frame to front of input buffer */
+ /*******************************************/
+ silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) );
+
+ if( !psEnc->sCmn.prefillFlag ) {
+ VARDECL( opus_int16, res_pitch );
+ VARDECL( opus_uint8, ec_buf_copy );
+ opus_int16 *res_pitch_frame;
+
+ ALLOC( res_pitch,
+ psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length
+ + psEnc->sCmn.ltp_mem_length, opus_int16 );
+ /* start of pitch LPC residual frame */
+ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length;
+
+ /*****************************************/
+ /* Find pitch lags, initial LPC analysis */
+ /*****************************************/
+ silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame - psEnc->sCmn.ltp_mem_length, psEnc->sCmn.arch );
+
+ /************************/
+ /* Noise shape analysis */
+ /************************/
+ silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch );
+
+ /***************************************************/
+ /* Find linear prediction coefficients (LPC + LTP) */
+ /***************************************************/
+ silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding );
+
+ /****************************************/
+ /* Process gains */
+ /****************************************/
+ silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding );
+
+ /****************************************/
+ /* Low Bitrate Redundant Encoding */
+ /****************************************/
+ silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding );
+
+ /* Loop over quantizer and entropy coding to control bitrate */
+ maxIter = 6;
+ gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+ found_lower = 0;
+ found_upper = 0;
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ gainsID_lower = -1;
+ gainsID_upper = -1;
+ /* Copy part of the input state */
+ silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+ silk_memcpy( &sNSQ_copy[0], &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ seed_copy = psEnc->sCmn.indices.Seed;
+ ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+ ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+ ALLOC( ec_buf_copy, 1275, opus_uint8 );
+ for( iter = 0; ; iter++ ) {
+ if( gainsID == gainsID_lower ) {
+ nBits = nBits_lower;
+ } else if( gainsID == gainsID_upper ) {
+ nBits = nBits_upper;
+ } else {
+ /* Restore part of the input state */
+ if( iter > 0 ) {
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy[0], sizeof( silk_nsq_state ) );
+ psEnc->sCmn.indices.Seed = seed_copy;
+ psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+ psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses,
+ sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14,
+ psEnc->sCmn.arch );
+ } else {
+ silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses,
+ sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14,
+ psEnc->sCmn.arch);
+ }
+
+ if ( iter == maxIter && !found_lower ) {
+ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+ }
+
+ /****************************************/
+ /* Encode Parameters */
+ /****************************************/
+ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+ /****************************************/
+ /* Encode Excitation Signal */
+ /****************************************/
+ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+ psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+ nBits = ec_tell( psRangeEnc );
+
+ /* If we still bust after the last iteration, do some damage control. */
+ if ( iter == maxIter && !found_lower && nBits > maxBits ) {
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+
+ /* Keep gains the same as the last frame. */
+ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ psEnc->sCmn.indices.GainsIndices[ i ] = 4;
+ }
+ if (condCoding != CODE_CONDITIONALLY) {
+ psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev;
+ }
+ psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+ psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+ /* Clear all pulses. */
+ for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) {
+ psEnc->sCmn.pulses[ i ] = 0;
+ }
+
+ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+ psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+ nBits = ec_tell( psRangeEnc );
+ }
+
+ if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+ break;
+ }
+ }
+
+ if( iter == maxIter ) {
+ if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+ /* Restore output state from earlier iteration that did meet the bitrate budget */
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+ celt_assert( sRangeEnc_copy2.offs <= 1275 );
+ silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy[1], sizeof( silk_nsq_state ) );
+ psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+ }
+ break;
+ }
+
+ if( nBits > maxBits ) {
+ if( found_lower == 0 && iter >= 2 ) {
+ /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+ sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 );
+ found_upper = 0;
+ gainsID_upper = -1;
+ } else {
+ found_upper = 1;
+ nBits_upper = nBits;
+ gainMult_upper = gainMult_Q8;
+ gainsID_upper = gainsID;
+ }
+ } else if( nBits < maxBits - bits_margin ) {
+ found_lower = 1;
+ nBits_lower = nBits;
+ gainMult_lower = gainMult_Q8;
+ if( gainsID != gainsID_lower ) {
+ gainsID_lower = gainsID;
+ /* Copy part of the output state */
+ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+ celt_assert( psRangeEnc->offs <= 1275 );
+ silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+ silk_memcpy( &sNSQ_copy[1], &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+ }
+ } else {
+ /* Close enough */
+ break;
+ }
+
+ if ( !found_lower && nBits > maxBits ) {
+ int j;
+ for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ int sum=0;
+ for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) {
+ sum += abs( psEnc->sCmn.pulses[j] );
+ }
+ if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) {
+ best_sum[i] = sum;
+ best_gain_mult[i] = gainMult_Q8;
+ } else {
+ gain_lock[i] = 1;
+ }
+ }
+ }
+ if( ( found_lower & found_upper ) == 0 ) {
+ /* Adjust gain according to high-rate rate/distortion curve */
+ if( nBits > maxBits ) {
+ gainMult_Q8 = silk_min_32( 1024, gainMult_Q8*3/2 );
+ } else {
+ gainMult_Q8 = silk_max_32( 64, gainMult_Q8*4/5 );
+ }
+ } else {
+ /* Adjust gain by interpolating */
+ gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower );
+ /* New gain multiplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+ if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+ } else
+ if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ opus_int16 tmp;
+ if ( gain_lock[i] ) {
+ tmp = best_gain_mult[i];
+ } else {
+ tmp = gainMult_Q8;
+ }
+ sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 );
+ }
+
+ /* Quantize gains */
+ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16,
+ &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Unique identifier of gains vector */
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ }
+ }
+
+ /* Update input buffer */
+ silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+ ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) );
+
+ /* Exit without entropy coding */
+ if( psEnc->sCmn.prefillFlag ) {
+ /* No payload */
+ *pnBytesOut = 0;
+ RESTORE_STACK;
+ return ret;
+ }
+
+ /* Parameters needed for next frame */
+ psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+ /****************************************/
+ /* Finalize payload */
+ /****************************************/
+ psEnc->sCmn.first_frame_after_reset = 0;
+ /* Payload size */
+ *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+ RESTORE_STACK;
+ return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ const opus_int16 x16[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+)
+{
+ opus_int32 TempGains_Q16[ MAX_NB_SUBFR ];
+ SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+ VARDECL(silk_nsq_state, sNSQ_LBRR);
+ SAVE_STACK;
+
+ /*******************************************/
+ /* Control use of inband LBRR */
+ /*******************************************/
+ if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+ /* Using ALLOC() instead of a regular stack allocation to minimize real stack use when using the pseudostack.
+ This is useful on some embedded systems. */
+ ALLOC(sNSQ_LBRR, 1, silk_nsq_state);
+
+ psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+ /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+ silk_memcpy( &sNSQ_LBRR[0], &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+ /* Save original gains */
+ silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+
+ if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+ /* First frame in packet or previous frame not LBRR coded */
+ psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+ /* Increase Gains to get target LBRR rate */
+ psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases;
+ psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+ }
+
+ /* Decode to get gains in sync with decoder */
+ /* Overwrite unquantized gains with quantized gains */
+ silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices,
+ &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR[0], psIndices_LBRR, x16,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+ psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch );
+ } else {
+ silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR[0], psIndices_LBRR, x16,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+ psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch );
+ }
+
+ /* Restore original gains */
+ silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Finds LPC vector from correlations, and converts to NLSF */
+void silk_find_LPC_FIX(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const opus_int16 x[], /* I Input signal */
+ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
+)
+{
+ opus_int k, subfr_length;
+ opus_int32 a_Q16[ MAX_LPC_ORDER ];
+ opus_int isInterpLower, shift;
+ opus_int32 res_nrg0, res_nrg1;
+ opus_int rshift0, rshift1;
+
+ /* Used only for LSF interpolation */
+ opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg;
+ opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
+ opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ];
+ opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ];
+ SAVE_STACK;
+
+ subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+ /* Default: no interpolation */
+ psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+ /* Burg AR analysis for the full frame */
+ silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch );
+
+ if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ VARDECL( opus_int16, LPC_res );
+
+ /* Optimal solution for last 10 ms */
+ silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch );
+
+ /* subtract residual energy here, as that's easier than adding it to the */
+ /* residual energy of the first 10 ms in each iteration of the search below */
+ shift = res_tmp_nrg_Q - res_nrg_Q;
+ if( shift >= 0 ) {
+ if( shift < 32 ) {
+ res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift );
+ }
+ } else {
+ silk_assert( shift > -32 );
+ res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg;
+ res_nrg_Q = res_tmp_nrg_Q;
+ }
+
+ /* Convert to NLSFs */
+ silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder );
+
+ ALLOC( LPC_res, 2 * subfr_length, opus_int16 );
+
+ /* Search over interpolation indices to find the one with lowest residual energy */
+ for( k = 3; k >= 0; k-- ) {
+ /* Interpolate NLSFs for first half */
+ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+ /* Convert to LPC for residual energy evaluation */
+ silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch );
+
+ /* Calculate residual energy with NLSF interpolation */
+ silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch );
+
+ silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder );
+ silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder );
+
+ /* Add subframe energies from first half frame */
+ shift = rshift0 - rshift1;
+ if( shift >= 0 ) {
+ res_nrg1 = silk_RSHIFT( res_nrg1, shift );
+ res_nrg_interp_Q = -rshift0;
+ } else {
+ res_nrg0 = silk_RSHIFT( res_nrg0, -shift );
+ res_nrg_interp_Q = -rshift1;
+ }
+ res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 );
+
+ /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
+ shift = res_nrg_interp_Q - res_nrg_Q;
+ if( shift >= 0 ) {
+ if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) {
+ isInterpLower = silk_TRUE;
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ } else {
+ if( -shift < 32 ) {
+ if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) {
+ isInterpLower = silk_TRUE;
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ }
+
+ /* Determine whether current interpolated NLSFs are best so far */
+ if( isInterpLower == silk_TRUE ) {
+ /* Interpolation has lower residual energy */
+ res_nrg = res_nrg_interp;
+ res_nrg_Q = res_nrg_interp_Q;
+ psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+ }
+ }
+ }
+
+ if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+ /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+ silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder );
+ }
+
+ celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "tuning_parameters.h"
+
+void silk_find_LTP_FIX(
+ opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */
+ opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */
+ const opus_int16 r_ptr[], /* I Residual signal after LPC */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, k, extra_shifts;
+ opus_int xx_shifts, xX_shifts, XX_shifts;
+ const opus_int16 *lag_ptr;
+ opus_int32 *XXLTP_Q17_ptr, *xXLTP_Q17_ptr;
+ opus_int32 xx, nrg, temp;
+
+ xXLTP_Q17_ptr = xXLTP_Q17;
+ XXLTP_Q17_ptr = XXLTP_Q17;
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+ silk_sum_sqr_shift( &xx, &xx_shifts, r_ptr, subfr_length + LTP_ORDER ); /* xx in Q( -xx_shifts ) */
+ silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, XXLTP_Q17_ptr, &nrg, &XX_shifts, arch ); /* XXLTP_Q17_ptr and nrg in Q( -XX_shifts ) */
+ extra_shifts = xx_shifts - XX_shifts;
+ if( extra_shifts > 0 ) {
+ /* Shift XX */
+ xX_shifts = xx_shifts;
+ for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
+ XXLTP_Q17_ptr[ i ] = silk_RSHIFT32( XXLTP_Q17_ptr[ i ], extra_shifts ); /* Q( -xX_shifts ) */
+ }
+ nrg = silk_RSHIFT32( nrg, extra_shifts ); /* Q( -xX_shifts ) */
+ } else if( extra_shifts < 0 ) {
+ /* Shift xx */
+ xX_shifts = XX_shifts;
+ xx = silk_RSHIFT32( xx, -extra_shifts ); /* Q( -xX_shifts ) */
+ } else {
+ xX_shifts = xx_shifts;
+ }
+ silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */
+
+ /* At this point all correlations are in Q(-xX_shifts) */
+ temp = silk_SMLAWB( 1, nrg, SILK_FIX_CONST( LTP_CORR_INV_MAX, 16 ) );
+ temp = silk_max( temp, xx );
+TIC(div)
+#if 0
+ for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
+ XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 );
+ }
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 );
+ }
+#else
+ for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
+ XXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)XXLTP_Q17_ptr[ i ], 17 ) / temp );
+ }
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp );
+ }
+#endif
+TOC(div)
+ r_ptr += subfr_length;
+ XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER;
+ xXLTP_Q17_ptr += LTP_ORDER;
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int16 res[], /* O residual */
+ const opus_int16 x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int buf_len, i, scale;
+ opus_int32 thrhld_Q13, res_nrg;
+ const opus_int16 *x_ptr;
+ VARDECL( opus_int16, Wsig );
+ opus_int16 *Wsig_ptr;
+ opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+ opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ];
+ opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ];
+ opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ];
+ SAVE_STACK;
+
+ /******************************************/
+ /* Set up buffer lengths etc based on Fs */
+ /******************************************/
+ buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+ /* Safety check */
+ celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+ /*************************************/
+ /* Estimate LPC AR coefficients */
+ /*************************************/
+
+ /* Calculate windowed signal */
+
+ ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 );
+
+ /* First LA_LTP samples */
+ x_ptr = x + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+ Wsig_ptr = Wsig;
+ silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch );
+
+ /* Middle un - windowed samples */
+ Wsig_ptr += psEnc->sCmn.la_pitch;
+ x_ptr += psEnc->sCmn.la_pitch;
+ silk_memcpy( Wsig_ptr, x_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) );
+
+ /* Last LA_LTP samples */
+ Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+ x_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+ silk_apply_sine_window( Wsig_ptr, x_ptr, 2, psEnc->sCmn.la_pitch );
+
+ /* Calculate autocorrelation sequence */
+ silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch );
+
+ /* Add white noise, as fraction of energy */
+ auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1;
+
+ /* Calculate the reflection coefficients using schur */
+ res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Prediction gain */
+ psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Convert From 32 bit Q24 to 16 bit Q12 coefs */
+ for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) {
+ A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) );
+ }
+
+ /* Do BWE */
+ silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) );
+
+ /*****************************************/
+ /* LPC analysis filtering */
+ /*****************************************/
+ silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch );
+
+ if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+ /* Threshold for pitch estimator */
+ thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 );
+ thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder );
+ thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 );
+ thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) );
+ thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 );
+ thrhld_Q13 = silk_SAT16( thrhld_Q13 );
+
+ /*****************************************/
+ /* Call pitch estimator */
+ /*****************************************/
+ if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex,
+ &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16,
+ (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr,
+ psEnc->sCmn.arch) == 0 )
+ {
+ psEnc->sCmn.indices.signalType = TYPE_VOICED;
+ } else {
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ }
+ } else {
+ silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+ psEnc->sCmn.indices.lagIndex = 0;
+ psEnc->sCmn.indices.contourIndex = 0;
+ psEnc->LTPCorr_Q15 = 0;
+ }
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+
+void silk_find_pred_coefs_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ const opus_int16 res_pitch[], /* I Residual from pitch analysis */
+ const opus_int16 x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i;
+ opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ];
+ /* Set to NLSF_Q15 to zero so we don't copy junk to the state. */
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]={0};
+ const opus_int16 *x_ptr;
+ opus_int16 *x_pre_ptr;
+ VARDECL( opus_int16, LPC_in_pre );
+ opus_int32 min_gain_Q16, minInvGain_Q30;
+ SAVE_STACK;
+
+ /* weighting for weighted least squares */
+ min_gain_Q16 = silk_int32_MAX >> 6;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] );
+ }
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ /* Divide to Q16 */
+ silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 );
+ /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
+ invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 );
+
+ /* Limit inverse */
+ invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 100 );
+
+ /* Square the inverted gains */
+ silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) );
+
+ /* Invert the inverted and normalized gains */
+ local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] );
+ }
+
+ ALLOC( LPC_in_pre,
+ psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder
+ + psEnc->sCmn.frame_length, opus_int16 );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ VARDECL( opus_int32, xXLTP_Q17 );
+ VARDECL( opus_int32, XXLTP_Q17 );
+
+ /**********/
+ /* VOICED */
+ /**********/
+ celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+ ALLOC( xXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER, opus_int32 );
+ ALLOC( XXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 );
+
+ /* LTP analysis */
+ silk_find_LTP_FIX( XXLTP_Q17, xXLTP_Q17, res_pitch,
+ psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch );
+
+ /* Quantize LTP gain parameters */
+ silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+ &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain_Q7, XXLTP_Q17, xXLTP_Q17, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch );
+
+ /* Control LTP scaling */
+ silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding );
+
+ /* Create LTP residual */
+ silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ } else {
+ /************/
+ /* UNVOICED */
+ /************/
+ /* Create signal with prepended subframes, scaled by inverse gains */
+ x_ptr = x - psEnc->sCmn.predictLPCOrder;
+ x_pre_ptr = LPC_in_pre;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ],
+ psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+ x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+ x_ptr += psEnc->sCmn.subfr_length;
+ }
+
+ silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) );
+ psEncCtrl->LTPredCodGain_Q7 = 0;
+ psEnc->sCmn.sum_log_gain_Q7 = 0;
+ psEncCtrl->LTP_scale_Q14 = 0;
+ }
+
+ /* Limit on total predictive coding gain */
+ if( psEnc->sCmn.first_frame_after_reset ) {
+ minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 );
+ } else {
+ minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */
+ minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30,
+ silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ),
+ silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 );
+ }
+
+ /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+ silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 );
+
+ /* Quantize LSFs */
+ silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+ /* Calculate residual energy using quantized LPC coefficients */
+ silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains,
+ psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch );
+
+ /* Copy to prediction struct for use in next frame for interpolation */
+ silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */
+ const opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 rc, tmp1, tmp2;
+
+ for( k = 0; k < order; k++ ) {
+ rc = rc_Q15[ k ];
+ for( n = 0; n < (k + 1) >> 1; n++ ) {
+ tmp1 = A_Q24[ n ];
+ tmp2 = A_Q24[ k - n - 1 ];
+ A_Q24[ n ] = silk_SMLAWB( tmp1, silk_LSHIFT( tmp2, 1 ), rc );
+ A_Q24[ k - n - 1 ] = silk_SMLAWB( tmp2, silk_LSHIFT( tmp1, 1 ), rc );
+ }
+ A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 );
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */
+ const opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 rc, tmp1, tmp2;
+
+ for( k = 0; k < order; k++ ) {
+ rc = rc_Q16[ k ];
+ for( n = 0; n < (k + 1) >> 1; n++ ) {
+ tmp1 = A_Q24[ n ];
+ tmp2 = A_Q24[ k - n - 1 ];
+ A_Q24[ n ] = silk_SMLAWW( tmp1, tmp2, rc );
+ A_Q24[ k - n - 1 ] = silk_SMLAWW( tmp2, tmp1, rc );
+ }
+ A_Q24[ k ] = -silk_LSHIFT( rc, 8 );
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FIX_H
+#define SILK_MAIN_FIX_H
+
+#include "SigProc_FIX.h"
+#include "structs_FIX.h"
+#include "control.h"
+#include "main.h"
+#include "PLC.h"
+#include "debug.h"
+#include "entenc.h"
+
+#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \
+ || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
+#include "fixed/arm/warped_autocorrelation_FIX_arm.h"
+#endif
+
+
+#define silk_encoder_state_Fxx silk_encoder_state_FIX
+#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX
+#define silk_encode_frame_Fxx silk_encode_frame_FIX
+
+#define QC 10
+#define QS 13
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int activity /* I Decision of Opus voice activity detector */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ int arch /* I Run-time architecture */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
+ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
+ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
+ int arch /* I Run-time architecture */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX_c(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+);
+
+#if !defined(OVERRIDE_silk_warped_autocorrelation_FIX)
+#define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \
+ ((void)(arch), silk_warped_autocorrelation_FIX_c(corr, scale, input, warping_Q16, length, order))
+#endif
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/**********************************************/
+/* Prediction Analysis */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int16 res[], /* O residual */
+ const opus_int16 x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ const opus_int16 res_pitch[], /* I Residual from pitch analysis */
+ const opus_int16 x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FIX(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const opus_int16 x[], /* I Input signal */
+ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FIX(
+ opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */
+ opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */
+ const opus_int16 r_lpc[], /* I Residual signal after LPC */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ int arch /* I Run-time architecture */
+);
+
+void silk_LTP_analysis_filter_FIX(
+ opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
+ const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
+ const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FIX(
+ opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
+ const opus_int16 x[], /* I Input signal */
+ opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int LPC_order, /* I LPC order */
+ int arch /* I Run-time architecture */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+ const opus_int16 *c, /* I Prediction vector */
+ const opus_int32 *wXX, /* I Correlation matrix */
+ const opus_int32 *wXx, /* I Correlation vector */
+ opus_int32 wxx, /* I Signal energy */
+ opus_int D, /* I Dimension */
+ opus_int cQ /* I Q value for c vector 0 - 15 */
+);
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
+ opus_int32 *nrg, /* O Energy of x vector */
+ opus_int *rshifts, /* O Right shifts of correlations */
+ int arch /* I Run-time architecture */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int16 *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
+ const opus_int rshifts, /* I Right shifts of correlations */
+ int arch /* I Run-time architecture */
+);
+
+#endif /* SILK_MAIN_FIX_H */
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+#include "tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters. */
+static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/
+ const opus_int32 *coefs_Q24,
+ opus_int lambda_Q16,
+ opus_int order
+) {
+ opus_int i;
+ opus_int32 gain_Q24;
+
+ lambda_Q16 = -lambda_Q16;
+ gain_Q24 = coefs_Q24[ order - 1 ];
+ for( i = order - 2; i >= 0; i-- ) {
+ gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 );
+ }
+ gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 );
+ return silk_INVERSE32_varQ( gain_Q24, 40 );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void limit_warped_coefs(
+ opus_int32 *coefs_Q24,
+ opus_int lambda_Q16,
+ opus_int32 limit_Q24,
+ opus_int order
+) {
+ opus_int i, iter, ind = 0;
+ opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_Q16;
+ opus_int32 nom_Q16, den_Q24;
+ opus_int32 limit_Q20, maxabs_Q20;
+
+ /* Convert to monic coefficients */
+ lambda_Q16 = -lambda_Q16;
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 );
+ }
+ lambda_Q16 = -lambda_Q16;
+ nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 );
+ gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ for( i = 0; i < order; i++ ) {
+ coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] );
+ }
+ limit_Q20 = silk_RSHIFT(limit_Q24, 4);
+ for( iter = 0; iter < 10; iter++ ) {
+ /* Find maximum absolute value */
+ maxabs_Q24 = -1;
+ for( i = 0; i < order; i++ ) {
+ tmp = silk_abs_int32( coefs_Q24[ i ] );
+ if( tmp > maxabs_Q24 ) {
+ maxabs_Q24 = tmp;
+ ind = i;
+ }
+ }
+ /* Use Q20 to avoid any overflow when multiplying by (ind + 1) later. */
+ maxabs_Q20 = silk_RSHIFT(maxabs_Q24, 4);
+ if( maxabs_Q20 <= limit_Q20 ) {
+ /* Coefficients are within range - done */
+ return;
+ }
+
+ /* Convert back to true warped coefficients */
+ for( i = 1; i < order; i++ ) {
+ coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 );
+ }
+ gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 );
+ for( i = 0; i < order; i++ ) {
+ coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] );
+ }
+
+ /* Apply bandwidth expansion */
+ chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ(
+ silk_SMULWB( maxabs_Q20 - limit_Q20, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ),
+ silk_MUL( maxabs_Q20, ind + 1 ), 22 );
+ silk_bwexpander_32( coefs_Q24, order, chirp_Q16 );
+
+ /* Convert to monic warped coefficients */
+ lambda_Q16 = -lambda_Q16;
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 );
+ }
+ lambda_Q16 = -lambda_Q16;
+ nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 );
+ gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ for( i = 0; i < order; i++ ) {
+ coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] );
+ }
+ }
+ silk_assert( 0 );
+}
+
+/**************************************************************/
+/* Compute noise shaping coefficients and initial gain values */
+/**************************************************************/
+void silk_noise_shape_analysis_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
+ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
+ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
+ int arch /* I Run-time architecture */
+)
+{
+ silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+ opus_int k, i, nSamples, nSegs, Qnrg, b_Q14, warping_Q16, scale = 0;
+ opus_int32 SNR_adj_dB_Q7, HarmShapeGain_Q16, Tilt_Q16, tmp32;
+ opus_int32 nrg, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
+ opus_int32 BWExp_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
+ opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 AR_Q24[ MAX_SHAPE_LPC_ORDER ];
+ VARDECL( opus_int16, x_windowed );
+ const opus_int16 *x_ptr, *pitch_res_ptr;
+ SAVE_STACK;
+
+ /* Point to start of first LPC analysis block */
+ x_ptr = x - psEnc->sCmn.la_shape;
+
+ /****************/
+ /* GAIN CONTROL */
+ /****************/
+ SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
+
+ /* Input quality is the average of the quality in the lowest two VAD bands */
+ psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+ + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
+
+ /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
+ psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
+ SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
+
+ /* Reduce coding SNR during low speech activity */
+ if( psEnc->sCmn.useCBR == 0 ) {
+ b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
+ b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+ silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/
+ silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce gains for periodic signals */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
+ } else {
+ /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+ silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
+ SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
+ }
+
+ /*************************/
+ /* SPARSENESS PROCESSING */
+ /*************************/
+ /* Set quantizer offset */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Initially set to 0; may be overruled in process_gains(..) */
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+ nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
+ energy_variation_Q7 = 0;
+ log_energy_prev_Q7 = 0;
+ pitch_res_ptr = pitch_res;
+ nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2;
+ for( k = 0; k < nSegs; k++ ) {
+ silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
+ nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/
+
+ log_energy_Q7 = silk_lin2log( nrg );
+ if( k > 0 ) {
+ energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
+ }
+ log_energy_prev_Q7 = log_energy_Q7;
+ pitch_res_ptr += nSamples;
+ }
+
+ /* Set quantization offset depending on sparseness measure */
+ if( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+ }
+
+ /*******************************/
+ /* Control bandwidth expansion */
+ /*******************************/
+ /* More BWE for signals with high prediction gain */
+ strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
+ BWExp_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
+ silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+ warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
+ } else {
+ warping_Q16 = 0;
+ }
+
+ /********************************************/
+ /* Compute noise shaping AR coefs and gains */
+ /********************************************/
+ ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Apply window: sine slope followed by flat part followed by cosine slope */
+ opus_int shift, slope_part, flat_part;
+ flat_part = psEnc->sCmn.fs_kHz * 3;
+ slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
+
+ silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
+ shift = slope_part;
+ silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
+ shift += flat_part;
+ silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+ /* Update pointer: next LPC analysis block */
+ x_ptr += psEnc->sCmn.subfr_length;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Calculate warped auto correlation */
+ silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch );
+ } else {
+ /* Calculate regular auto correlation */
+ silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
+ }
+
+ /* Add white noise, as a fraction of energy */
+ auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
+ SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
+
+ /* Calculate the reflection coefficients using schur */
+ nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
+ silk_assert( nrg >= 0 );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
+
+ Qnrg = -scale; /* range: -12...30*/
+ silk_assert( Qnrg >= -12 );
+ silk_assert( Qnrg <= 30 );
+
+ /* Make sure that Qnrg is an even number */
+ if( Qnrg & 1 ) {
+ Qnrg -= 1;
+ nrg >>= 1;
+ }
+
+ tmp32 = silk_SQRT_APPROX( nrg );
+ Qnrg >>= 1; /* range: -6...15*/
+
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Adjust gain for warping */
+ gain_mult_Q16 = warped_gain( AR_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
+ silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 );
+ if( psEncCtrl->Gains_Q16[ k ] < SILK_FIX_CONST( 0.25, 16 ) ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+ } else {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 );
+ if ( psEncCtrl->Gains_Q16[ k ] >= ( silk_int32_MAX >> 1 ) ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
+ } else {
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT32( psEncCtrl->Gains_Q16[ k ], 1 );
+ }
+ }
+ silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 );
+ }
+
+ /* Bandwidth expansion */
+ silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Convert to monic warped prediction coefficients and limit absolute values */
+ limit_warped_coefs( AR_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
+
+ /* Convert from Q24 to Q13 and store in int16 */
+ for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
+ psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR_Q24[ i ], 11 ) );
+ }
+ } else {
+ silk_LPC_fit( &psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER ], AR_Q24, 13, 24, psEnc->sCmn.shapingLPCOrder );
+ }
+ }
+
+ /*****************/
+ /* Gain tweaking */
+ /*****************/
+ /* Increase gains during low speech activity and put lower limit on gains */
+ gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
+ gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
+ silk_assert( gain_mult_Q16 > 0 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+ silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+ psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
+ }
+
+
+ /************************************************/
+ /* Control low-frequency shaping and noise tilt */
+ /************************************************/
+ /* Less low frequency shaping for noisy inputs */
+ strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
+ SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
+ strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+ /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+ opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
+ /* Pack two coefficients in one int32 */
+ psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
+ psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+ }
+ silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
+ Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
+ silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
+ silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
+ } else {
+ b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
+ /* Pack two coefficients in one int32 */
+ psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
+ silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
+ psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+ for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
+ }
+ Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
+ }
+
+ /****************************/
+ /* HARMONIC SHAPING CONTROL */
+ /****************************/
+ if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* More harmonic noise shaping for high bitrates or noisy input */
+ HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
+ SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
+ psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
+
+ /* Less harmonic noise shaping for less periodic signals */
+ HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
+ silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
+ } else {
+ HarmShapeGain_Q16 = 0;
+ }
+
+ /*************************/
+ /* Smooth over subframes */
+ /*************************/
+ for( k = 0; k < MAX_NB_SUBFR; k++ ) {
+ psShapeSt->HarmShapeGain_smth_Q16 =
+ silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+ psShapeSt->Tilt_smth_Q16 =
+ silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+
+ psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
+ psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 );
+ }
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "SigProc_FIX.h"
+#include "pitch_est_defines.h"
+#include "stack_alloc.h"
+#include "debug.h"
+#include "pitch.h"
+
+#define SCRATCH_SIZE 22
+#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 )
+#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 )
+#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 )
+#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 )
+#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 )
+#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 )
+#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ )
+#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) )
+#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 )
+#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 )
+#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN )
+
+typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ];
+
+/************************************************************/
+/* Internally used functions */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
+ const opus_int16 frame[], /* I vector to correlate */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of a 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+ silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
+ const opus_int16 frame[], /* I vector to calc energy in */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of one 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+);
+
+/*************************************************************/
+/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */
+/*************************************************************/
+opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const opus_int16 *frame_unscaled, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O 4 pitch lag values */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
+ const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I Sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ VARDECL( opus_int16, frame_8kHz_buf );
+ VARDECL( opus_int16, frame_4kHz );
+ VARDECL( opus_int16, frame_scaled );
+ opus_int32 filt_state[ 6 ];
+ const opus_int16 *frame, *frame_8kHz;
+ opus_int i, k, d, j;
+ VARDECL( opus_int16, C );
+ VARDECL( opus_int32, xcorr32 );
+ const opus_int16 *target_ptr, *basis_ptr;
+ opus_int32 cross_corr, normalizer, energy, energy_basis, energy_target;
+ opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp, shift;
+ VARDECL( opus_int16, d_comp );
+ opus_int32 sum, threshold, lag_counter;
+ opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new;
+ opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+ VARDECL( silk_pe_stage3_vals, energies_st3 );
+ VARDECL( silk_pe_stage3_vals, cross_corr_st3 );
+ opus_int frame_length, frame_length_8kHz, frame_length_4kHz;
+ opus_int sf_length;
+ opus_int min_lag;
+ opus_int max_lag;
+ opus_int32 contour_bias_Q15, diff;
+ opus_int nb_cbk_search, cbk_size;
+ opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13;
+ const opus_int8 *Lag_CB_ptr;
+ SAVE_STACK;
+
+ /* Check for valid sampling frequency */
+ celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+ /* Check for valid complexity setting */
+ celt_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ celt_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) );
+ silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) );
+
+ /* Set up frame lengths max / min lag for the sampling frequency */
+ frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+ frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+ frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+ sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz;
+ min_lag = PE_MIN_LAG_MS * Fs_kHz;
+ max_lag = PE_MAX_LAG_MS * Fs_kHz - 1;
+
+ /* Downscale input if necessary */
+ silk_sum_sqr_shift( &energy, &shift, frame_unscaled, frame_length );
+ shift += 3 - silk_CLZ32( energy ); /* at least two bits headroom */
+ ALLOC( frame_scaled, frame_length, opus_int16 );
+ if( shift > 0 ) {
+ shift = silk_RSHIFT( shift + 1, 1 );
+ for( i = 0; i < frame_length; i++ ) {
+ frame_scaled[ i ] = silk_RSHIFT( frame_unscaled[ i ], shift );
+ }
+ frame = frame_scaled;
+ } else {
+ frame = frame_unscaled;
+ }
+
+ ALLOC( frame_8kHz_buf, ( Fs_kHz == 8 ) ? 1 : frame_length_8kHz, opus_int16 );
+ /* Resample from input sampled at Fs_kHz to 8 kHz */
+ if( Fs_kHz == 16 ) {
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_8kHz_buf, frame, frame_length );
+ frame_8kHz = frame_8kHz_buf;
+ } else if( Fs_kHz == 12 ) {
+ silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+ silk_resampler_down2_3( filt_state, frame_8kHz_buf, frame, frame_length );
+ frame_8kHz = frame_8kHz_buf;
+ } else {
+ celt_assert( Fs_kHz == 8 );
+ frame_8kHz = frame;
+ }
+
+ /* Decimate again to 4 kHz */
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */
+ ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 );
+ silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz );
+
+ /* Low-pass filter */
+ for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+ frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] );
+ }
+
+
+ /******************************************************************************
+ * FIRST STAGE, operating in 4 khz
+ ******************************************************************************/
+ ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 );
+ ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 );
+ silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) );
+ target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ];
+ for( k = 0; k < nb_subfr >> 1; k++ ) {
+ /* Check that we are within range of the array */
+ celt_assert( target_ptr >= frame_4kHz );
+ celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ basis_ptr = target_ptr - MIN_LAG_4KHZ;
+
+ /* Check that we are within range of the array */
+ celt_assert( basis_ptr >= frame_4kHz );
+ celt_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch );
+
+ /* Calculate first vector products before loop */
+ cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ];
+ normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch );
+ normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ) );
+ normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) );
+
+ matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
+
+ /* From now on normalizer is computed recursively */
+ for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) {
+ basis_ptr--;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ cross_corr = xcorr32[ MAX_LAG_4KHZ - d ];
+
+ /* Add contribution of new sample and remove contribution from oldest sample */
+ normalizer = silk_ADD32( normalizer,
+ silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) -
+ silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) );
+
+ matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
+ }
+ /* Update target pointer */
+ target_ptr += SF_LENGTH_8KHZ;
+ }
+
+ /* Combine two subframes into single correlation measure and apply short-lag bias */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+ sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ )
+ + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */
+ sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
+ C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
+ }
+ } else {
+ /* Only short-lag bias */
+ for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+ sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */
+ sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
+ C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
+ }
+ }
+
+ /* Sort */
+ length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 );
+ celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+ silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ,
+ length_d_srch );
+
+ /* Escape if correlation is very low already here */
+ Cmax = (opus_int)C[ 0 ]; /* Q14 */
+ if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) {
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr_Q15 = 0;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ RESTORE_STACK;
+ return 1;
+ }
+
+ threshold = silk_SMULWB( search_thres1_Q16, Cmax );
+ for( i = 0; i < length_d_srch; i++ ) {
+ /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+ if( C[ i ] > threshold ) {
+ d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 );
+ } else {
+ length_d_srch = i;
+ break;
+ }
+ }
+ celt_assert( length_d_srch > 0 );
+
+ ALLOC( d_comp, D_COMP_STRIDE, opus_int16 );
+ for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) {
+ d_comp[ i - D_COMP_MIN ] = 0;
+ }
+ for( i = 0; i < length_d_srch; i++ ) {
+ d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1;
+ }
+
+ /* Convolution */
+ for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+ d_comp[ i - D_COMP_MIN ] +=
+ d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ];
+ }
+
+ length_d_srch = 0;
+ for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) {
+ if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) {
+ d_srch[ length_d_srch ] = i;
+ length_d_srch++;
+ }
+ }
+
+ /* Convolution */
+ for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+ d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ]
+ + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ];
+ }
+
+ length_d_comp = 0;
+ for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) {
+ if( d_comp[ i - D_COMP_MIN ] > 0 ) {
+ d_comp[ length_d_comp ] = i - 2;
+ length_d_comp++;
+ }
+ }
+
+ /**********************************************************************************
+ ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+ *************************************************************************************/
+
+ /*********************************************************************************
+ * Find energy of each subframe projected onto its history, for a range of delays
+ *********************************************************************************/
+ silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) );
+
+ target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ for( k = 0; k < nb_subfr; k++ ) {
+
+ /* Check that we are within range of the array */
+ celt_assert( target_ptr >= frame_8kHz );
+ celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+ energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 );
+ for( j = 0; j < length_d_comp; j++ ) {
+ d = d_comp[ j ];
+ basis_ptr = target_ptr - d;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_8kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+ cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch );
+ if( cross_corr > 0 ) {
+ energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch );
+ matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr,
+ silk_ADD32( energy_target,
+ energy_basis ),
+ 13 + 1 ); /* Q13 */
+ } else {
+ matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0;
+ }
+ }
+ target_ptr += SF_LENGTH_8KHZ;
+ }
+
+ /* search over lag range and lags codebook */
+ /* scale factor for lag codebook, as a function of center lag */
+
+ CCmax = silk_int32_MIN;
+ CCmax_b = silk_int32_MIN;
+
+ CBimax = 0; /* To avoid returning undefined lag values */
+ lag = -1; /* To check if lag with strong enough correlation has been found */
+
+ if( prevLag > 0 ) {
+ if( Fs_kHz == 12 ) {
+ prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 );
+ } else if( Fs_kHz == 16 ) {
+ prevLag = silk_RSHIFT( prevLag, 1 );
+ }
+ prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag );
+ } else {
+ prevLag_log2_Q7 = 0;
+ }
+ silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) );
+ /* Set up stage 2 codebook based on number of subframes */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+ /* If input is 8 khz use a larger codebook here because it is last stage */
+ nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE2;
+ }
+ } else {
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE2_10MS;
+ }
+
+ for( k = 0; k < length_d_srch; k++ ) {
+ d = d_srch[ k ];
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ CC[ j ] = 0;
+ for( i = 0; i < nb_subfr; i++ ) {
+ opus_int d_subfr;
+ /* Try all codebooks */
+ d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size );
+ CC[ j ] = CC[ j ]
+ + (opus_int32)matrix_ptr( C, i,
+ d_subfr - ( MIN_LAG_8KHZ - 2 ),
+ CSTRIDE_8KHZ );
+ }
+ }
+ /* Find best codebook */
+ CCmax_new = silk_int32_MIN;
+ CBimax_new = 0;
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ if( CC[ i ] > CCmax_new ) {
+ CCmax_new = CC[ i ];
+ CBimax_new = i;
+ }
+ }
+
+ /* Bias towards shorter lags */
+ lag_log2_Q7 = silk_lin2log( d ); /* Q7 */
+ silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) );
+ silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) );
+ CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */
+
+ /* Bias towards previous lag */
+ silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) );
+ if( prevLag > 0 ) {
+ delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7;
+ silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) );
+ delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 );
+ prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */
+ prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) );
+ CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */
+ }
+
+ if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
+ CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */
+ silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */
+ ) {
+ CCmax_b = CCmax_new_b;
+ CCmax = CCmax_new;
+ lag = d;
+ CBimax = CBimax_new;
+ }
+ }
+
+ if( lag == -1 ) {
+ /* No suitable candidate found */
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr_Q15 = 0;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ RESTORE_STACK;
+ return 1;
+ }
+
+ /* Output normalized correlation */
+ *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 );
+ silk_assert( *LTPCorr_Q15 >= 0 );
+
+ if( Fs_kHz > 8 ) {
+ /* Search in original signal */
+
+ CBimax_old = CBimax;
+ /* Compensate for decimation */
+ silk_assert( lag == silk_SAT16( lag ) );
+ if( Fs_kHz == 12 ) {
+ lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 );
+ } else if( Fs_kHz == 16 ) {
+ lag = silk_LSHIFT( lag, 1 );
+ } else {
+ lag = silk_SMULBB( lag, 3 );
+ }
+
+ lag = silk_LIMIT_int( lag, min_lag, max_lag );
+ start_lag = silk_max_int( lag - 2, min_lag );
+ end_lag = silk_min_int( lag + 2, max_lag );
+ lag_new = lag; /* to avoid undefined lag */
+ CBimax = 0; /* to avoid undefined lag */
+
+ CCmax = silk_int32_MIN;
+ /* pitch lags according to second stage */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ];
+ }
+
+ /* Set up codebook parameters according to complexity setting and frame length */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ }
+
+ /* Calculate the correlations and energies needed in stage 3 */
+ ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+ ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+ silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
+ silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
+
+ lag_counter = 0;
+ silk_assert( lag == silk_SAT16( lag ) );
+ contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag );
+
+ target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+ energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 1 );
+ for( d = start_lag; d <= end_lag; d++ ) {
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ cross_corr = 0;
+ energy = energy_target;
+ for( k = 0; k < nb_subfr; k++ ) {
+ cross_corr = silk_ADD32( cross_corr,
+ matrix_ptr( cross_corr_st3, k, j,
+ nb_cbk_search )[ lag_counter ] );
+ energy = silk_ADD32( energy,
+ matrix_ptr( energies_st3, k, j,
+ nb_cbk_search )[ lag_counter ] );
+ silk_assert( energy >= 0 );
+ }
+ if( cross_corr > 0 ) {
+ CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */
+ /* Reduce depending on flatness of contour */
+ diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */
+ silk_assert( diff == silk_SAT16( diff ) );
+ CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */
+ } else {
+ CCmax_new = 0;
+ }
+
+ if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+ CCmax = CCmax_new;
+ lag_new = d;
+ CBimax = j;
+ }
+ }
+ lag_counter++;
+ }
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+ }
+ *lagIndex = (opus_int16)( lag_new - min_lag);
+ *contourIndex = (opus_int8)CBimax;
+ } else { /* Fs_kHz == 8 */
+ /* Save Lags */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 );
+ }
+ *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ );
+ *contourIndex = (opus_int8)CBimax;
+ }
+ celt_assert( *lagIndex >= 0 );
+ /* return as voiced */
+ RESTORE_STACK;
+ return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
+ const opus_int16 frame[], /* I vector to correlate */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of a 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+)
+{
+ const opus_int16 *target_ptr;
+ opus_int i, j, k, lag_counter, lag_low, lag_high;
+ opus_int nb_cbk_search, delta, idx, cbk_size;
+ VARDECL( opus_int32, scratch_mem );
+ VARDECL( opus_int32, xcorr32 );
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+ SAVE_STACK;
+
+ celt_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ celt_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+ ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 );
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the correlations for each subframe */
+ lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+ celt_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+ celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch );
+ for( j = lag_low; j <= lag_high; j++ ) {
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ];
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] =
+ scratch_mem[ idx + j ];
+ }
+ }
+ target_ptr += sf_length;
+ }
+ RESTORE_STACK;
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively. */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+ silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
+ const opus_int16 frame[], /* I vector to calc energy in */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of one 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+)
+{
+ const opus_int16 *target_ptr, *basis_ptr;
+ opus_int32 energy;
+ opus_int k, i, j, lag_counter;
+ opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff;
+ VARDECL( opus_int32, scratch_mem );
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+ SAVE_STACK;
+
+ celt_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ celt_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the energy for first lag */
+ basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+ energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch );
+ silk_assert( energy >= 0 );
+ scratch_mem[ lag_counter ] = energy;
+ lag_counter++;
+
+ lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+ for( i = 1; i < lag_diff; i++ ) {
+ /* remove part outside new window */
+ energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] );
+ silk_assert( energy >= 0 );
+
+ /* add part that comes into window */
+ energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) );
+ silk_assert( energy >= 0 );
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = energy;
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] =
+ scratch_mem[ idx + j ];
+ silk_assert(
+ matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 );
+ }
+ }
+ target_ptr += sf_length;
+ }
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+ opus_int k;
+ opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10;
+
+ /* Gain reduction when LTP coding gain is high */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */
+ s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 );
+ }
+ }
+
+ /* Limit the quantized signal */
+ /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */
+ InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin(
+ silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length );
+
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Soft limit on ratio residual energy and squared gains */
+ ResNrg = psEncCtrl->ResNrg[ k ];
+ ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 );
+ if( psEncCtrl->ResNrgQ[ k ] > 0 ) {
+ ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] );
+ } else {
+ if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) {
+ ResNrgPart = silk_int32_MAX;
+ } else {
+ ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] );
+ }
+ }
+ gain = psEncCtrl->Gains_Q16[ k ];
+ gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) );
+ if( gain_squared < silk_int16_MAX ) {
+ /* recalculate with higher precision */
+ gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain );
+ silk_assert( gain_squared > 0 );
+ gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */
+ gain = silk_min( gain, silk_int32_MAX >> 8 );
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */
+ } else {
+ gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */
+ gain = silk_min( gain, silk_int32_MAX >> 16 );
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */
+ }
+ }
+
+ /* Save unquantized gains and gain Index */
+ silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+ /* Quantize gains */
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
+ &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+ }
+
+ /* Quantizer boundary adjustment */
+ quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ];
+ psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 )
+ + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 );
+
+ silk_assert( psEncCtrl->Lambda_Q10 > 0 );
+ silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) );
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+ opus_int32 *XX, /* I/O Correlation matrices */
+ opus_int32 *xx, /* I/O Correlation values */
+ opus_int32 noise, /* I Noise to add */
+ opus_int D /* I Dimension of XX */
+)
+{
+ opus_int i;
+ for( i = 0; i < D; i++ ) {
+ matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise );
+ }
+ xx[ 0 ] += noise;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+ const opus_int16 *c, /* I Prediction vector */
+ const opus_int32 *wXX, /* I Correlation matrix */
+ const opus_int32 *wXx, /* I Correlation vector */
+ opus_int32 wxx, /* I Signal energy */
+ opus_int D, /* I Dimension */
+ opus_int cQ /* I Q value for c vector 0 - 15 */
+)
+{
+ opus_int i, j, lshifts, Qxtra;
+ opus_int32 c_max, w_max, tmp, tmp2, nrg;
+ opus_int cn[ MAX_MATRIX_SIZE ];
+ const opus_int32 *pRow;
+
+ /* Safety checks */
+ celt_assert( D >= 0 );
+ celt_assert( D <= 16 );
+ celt_assert( cQ > 0 );
+ celt_assert( cQ < 16 );
+
+ lshifts = 16 - cQ;
+ Qxtra = lshifts;
+
+ c_max = 0;
+ for( i = 0; i < D; i++ ) {
+ c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) );
+ }
+ Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 );
+
+ w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] );
+ Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 );
+ Qxtra = silk_max_int( Qxtra, 0 );
+ for( i = 0; i < D; i++ ) {
+ cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra );
+ silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */
+ }
+ lshifts -= Qxtra;
+
+ /* Compute wxx - 2 * wXx * c */
+ tmp = 0;
+ for( i = 0; i < D; i++ ) {
+ tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] );
+ }
+ nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */
+
+ /* Add c' * wXX * c, assuming wXX is symmetric */
+ tmp2 = 0;
+ for( i = 0; i < D; i++ ) {
+ tmp = 0;
+ pRow = &wXX[ i * D ];
+ for( j = i + 1; j < D; j++ ) {
+ tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] );
+ }
+ tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] );
+ tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] );
+ }
+ nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */
+
+ /* Keep one bit free always, because we add them for LSF interpolation */
+ if( nrg < 1 ) {
+ nrg = 1;
+ } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) {
+ nrg = silk_int32_MAX >> 1;
+ } else {
+ nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */
+ }
+ return nrg;
+
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+#include "stack_alloc.h"
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FIX(
+ opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
+ const opus_int16 x[], /* I Input signal */
+ opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int LPC_order, /* I LPC order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int offset, i, j, rshift, lz1, lz2;
+ opus_int16 *LPC_res_ptr;
+ VARDECL( opus_int16, LPC_res );
+ const opus_int16 *x_ptr;
+ opus_int32 tmp32;
+ SAVE_STACK;
+
+ x_ptr = x;
+ offset = LPC_order + subfr_length;
+
+ /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+ ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 );
+ celt_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr );
+ for( i = 0; i < nb_subfr >> 1; i++ ) {
+ /* Calculate half frame LPC residual signal including preceding samples */
+ silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch );
+
+ /* Point to first subframe of the just calculated LPC residual signal */
+ LPC_res_ptr = LPC_res + LPC_order;
+ for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) {
+ /* Measure subframe energy */
+ silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length );
+
+ /* Set Q values for the measured energy */
+ nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift;
+
+ /* Move to next subframe */
+ LPC_res_ptr += offset;
+ }
+ /* Move to next frame half */
+ x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset;
+ }
+
+ /* Apply the squared subframe gains */
+ for( i = 0; i < nb_subfr; i++ ) {
+ /* Fully upscale gains and energies */
+ lz1 = silk_CLZ32( nrgs[ i ] ) - 1;
+ lz2 = silk_CLZ32( gains[ i ] ) - 1;
+
+ tmp32 = silk_LSHIFT32( gains[ i ], lz2 );
+
+ /* Find squared gains */
+ tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/
+
+ /* Scale energies */
+ nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/
+ nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32;
+ }
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Slower than schur(), but more accurate. */
+/* Uses SMULL(), available on armv4 */
+opus_int32 silk_schur64( /* O returns residual energy */
+ opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */
+ const opus_int32 c[], /* I Correlations [order+1] */
+ opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31;
+
+ celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC );
+
+ /* Check for invalid input */
+ if( c[ 0 ] <= 0 ) {
+ silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) );
+ return 0;
+ }
+
+ k = 0;
+ do {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+ } while( ++k <= order );
+
+ for( k = 0; k < order; k++ ) {
+ /* Check that we won't be getting an unstable rc, otherwise stop here. */
+ if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+ if ( C[ k + 1 ][ 0 ] > 0 ) {
+ rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 );
+ } else {
+ rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 );
+ }
+ k++;
+ break;
+ }
+
+ /* Get reflection coefficient: divide two Q30 values and get result in Q31 */
+ rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 );
+
+ /* Save the output */
+ rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 );
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1_Q30 = C[ n + k + 1 ][ 0 ];
+ Ctmp2_Q30 = C[ n ][ 1 ];
+
+ /* Multiply and add the highest int32 */
+ C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 );
+ C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 );
+ }
+ }
+
+ for(; k < order; k++ ) {
+ rc_Q16[ k ] = 0;
+ }
+
+ return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+
+/* Faster than schur64(), but much less accurate. */
+/* uses SMLAWB(), requiring armv5E and higher. */
+opus_int32 silk_schur( /* O Returns residual energy */
+ opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */
+ const opus_int32 *c, /* I correlations [order+1] */
+ const opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n, lz;
+ opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15;
+
+ celt_assert( order >= 0 && order <= SILK_MAX_ORDER_LPC );
+
+ /* Get number of leading zeros */
+ lz = silk_CLZ32( c[ 0 ] );
+
+ /* Copy correlations and adjust level to Q30 */
+ k = 0;
+ if( lz < 2 ) {
+ /* lz must be 1, so shift one to the right */
+ do {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 );
+ } while( ++k <= order );
+ } else if( lz > 2 ) {
+ /* Shift to the left */
+ lz -= 2;
+ do {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz );
+ } while( ++k <= order );
+ } else {
+ /* No need to shift */
+ do {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+ } while( ++k <= order );
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Check that we won't be getting an unstable rc, otherwise stop here. */
+ if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+ if ( C[ k + 1 ][ 0 ] > 0 ) {
+ rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 );
+ } else {
+ rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 );
+ }
+ k++;
+ break;
+ }
+
+ /* Get reflection coefficient */
+ rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) );
+
+ /* Clip (shouldn't happen for properly conditioned inputs) */
+ rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 );
+
+ /* Store */
+ rc_Q15[ k ] = (opus_int16)rc_tmp_Q15;
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1 = C[ n + k + 1 ][ 0 ];
+ Ctmp2 = C[ n ][ 1 ];
+ C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 );
+ C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 );
+ }
+ }
+
+ for(; k < order; k++ ) {
+ rc_Q15[ k ] = 0;
+ }
+
+ /* return residual energy */
+ return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FIX_H
+#define SILK_STRUCTS_FIX_H
+
+#include "typedef.h"
+#include "main.h"
+#include "structs.h"
+
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+ opus_int8 LastGainIndex;
+ opus_int32 HarmBoost_smth_Q16;
+ opus_int32 HarmShapeGain_smth_Q16;
+ opus_int32 Tilt_smth_Q16;
+} silk_shape_state_FIX;
+
+/********************************/
+/* Encoder state FIX */
+/********************************/
+typedef struct {
+ silk_encoder_state sCmn; /* Common struct, shared with floating-point code */
+ silk_shape_state_FIX sShape; /* Shape state */
+
+ /* Buffer for find pitch and noise shape analysis */
+ silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+ opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */
+ opus_int32 resNrgSmth;
+} silk_encoder_state_FIX;
+
+/************************/
+/* Encoder control FIX */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+ opus_int pitchL[ MAX_NB_SUBFR ];
+
+ /* Noise shaping parameters */
+ /* Testing */
+ silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */
+ opus_int Tilt_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+ opus_int Lambda_Q10;
+ opus_int input_quality_Q14;
+ opus_int coding_quality_Q14;
+
+ /* measures */
+ opus_int32 predGain_Q16;
+ opus_int LTPredCodGain_Q7;
+ opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
+ opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */
+
+ /* Parameters for CBR mode */
+ opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
+ opus_int8 lastGainIndexPrev;
+} silk_encoder_control_FIX;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+ stereo_enc_state sStereo;
+ opus_int32 nBitsUsedLBRR;
+ opus_int32 nBitsExceeded;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int nPrevChannelsInternal;
+ opus_int timeSinceSwitchAllowed_ms;
+ opus_int allowBandwidthSwitch;
+ opus_int prev_decode_only_middle;
+ /* This needs to be last so we can skip the second state for mono. */
+ silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ];
+} silk_encoder;
+
+
+#endif
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "SigProc_FIX.h"
+#include "pitch.h"
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+ opus_int16 *data_out,
+ const opus_int16 *data_in,
+ opus_int32 gain_Q16, /* I Gain in Q16 */
+ const opus_int dataSize /* I Length */
+)
+{
+ opus_int i;
+ opus_int32 tmp32;
+
+ for( i = 0; i < dataSize; i++ ) {
+ tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] );
+ data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 );
+ }
+}
+
+/* Multiply a vector by a constant */
+void silk_scale_vector32_Q26_lshift_18(
+ opus_int32 *data1, /* I/O Q0/Q18 */
+ opus_int32 gain_Q26, /* I Q26 */
+ opus_int dataSize /* I length */
+)
+{
+ opus_int i;
+
+ for( i = 0; i < dataSize; i++ ) {
+ data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */
+ }
+}
+
+/* sum = for(i=0;i<len;i++)inVec1[i]*inVec2[i]; --- inner product */
+/* Note for ARM asm: */
+/* * inVec1 and inVec2 should be at least 2 byte aligned. */
+/* * len should be positive 16bit integer. */
+/* * only when len>6, memory access can be reduced by half. */
+opus_int32 silk_inner_prod_aligned(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int len, /* I vector lengths */
+ int arch /* I Run-time architecture */
+)
+{
+#ifdef FIXED_POINT
+ return celt_inner_prod(inVec1, inVec2, len, arch);
+#else
+ opus_int i;
+ opus_int32 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+ return sum;
+#endif
+}
+
+opus_int64 silk_inner_prod16_c(
+ const opus_int16 *inVec1, /* I input vector 1 */
+ const opus_int16 *inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int64 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+ return sum;
+}
--- /dev/null
+/* 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 "SigProc_FIX.h"
+#include "pitch.h"
+#include "celt/x86/x86cpu.h"
+
+opus_int64 silk_inner_prod16_sse4_1(
+ const opus_int16 *inVec1, /* I input vector 1 */
+ const opus_int16 *inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i, dataSize4;
+ opus_int64 sum;
+
+ __m128i xmm_prod_20, xmm_prod_31;
+ __m128i inVec1_3210, acc1;
+ __m128i inVec2_3210, acc2;
+
+ sum = 0;
+ dataSize4 = len & ~3;
+
+ acc1 = _mm_setzero_si128();
+ acc2 = _mm_setzero_si128();
+
+ for( i = 0; i < dataSize4; i += 4 ) {
+ inVec1_3210 = OP_CVTEPI16_EPI32_M64( &inVec1[i + 0] );
+ inVec2_3210 = OP_CVTEPI16_EPI32_M64( &inVec2[i + 0] );
+ xmm_prod_20 = _mm_mul_epi32( inVec1_3210, inVec2_3210 );
+
+ inVec1_3210 = _mm_shuffle_epi32( inVec1_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+ inVec2_3210 = _mm_shuffle_epi32( inVec2_3210, _MM_SHUFFLE( 0, 3, 2, 1 ) );
+ xmm_prod_31 = _mm_mul_epi32( inVec1_3210, inVec2_3210 );
+
+ acc1 = _mm_add_epi64( acc1, xmm_prod_20 );
+ acc2 = _mm_add_epi64( acc2, xmm_prod_31 );
+ }
+
+ acc1 = _mm_add_epi64( acc1, acc2 );
+
+ /* equal shift right 8 bytes */
+ acc2 = _mm_shuffle_epi32( acc1, _MM_SHUFFLE( 0, 0, 3, 2 ) );
+ acc1 = _mm_add_epi64( acc1, acc2 );
+
+ _mm_storel_epi64( (__m128i *)(void *)&sum, acc1 );
+
+ for( ; i < len; i++ ) {
+ sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+
+#ifdef OPUS_CHECK_ASM
+ {
+ opus_int64 sum_c = silk_inner_prod16_c( inVec1, inVec2, len );
+ silk_assert( sum == sum_c );
+ }
+#endif
+
+ return sum;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+#if defined(__mips)
+#include "mips/warped_autocorrelation_FIX_mipsr1.h"
+#endif
+
+
+/* Autocorrelations for a warped frequency axis */
+#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c
+void silk_warped_autocorrelation_FIX_c(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+)
+{
+ opus_int n, i, lsh;
+ opus_int32 tmp1_QS, tmp2_QS;
+ opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+ opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+
+ /* Order must be even */
+ celt_assert( ( order & 1 ) == 0 );
+ silk_assert( 2 * QS - QC >= 0 );
+
+ /* Loop over samples */
+ for( n = 0; n < length; n++ ) {
+ tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+ state_QS[ i ] = tmp1_QS;
+ corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ /* Output of allpass section */
+ tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+ state_QS[ i + 1 ] = tmp2_QS;
+ corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ }
+ state_QS[ order ] = tmp1_QS;
+ corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ }
+
+ lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35;
+ lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
+ *scale = -( QC + lsh );
+ silk_assert( *scale >= -30 && *scale <= 12 );
+ if( lsh >= 0 ) {
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) );
+ }
+ } else {
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) );
+ }
+ }
+ silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
+}
+#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */
--- /dev/null
+/***********************************************************************
+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 */
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__
+#define __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main_FIX.h"
+
+#if defined (__mips_dsp) && __mips == 32
+
+#define MIPS_MADD __builtin_mips_madd
+#define MIPS_SHILO __builtin_mips_shilo
+
+#define OVERRIDE_silk_warped_autocorrelation_FIX_c
+
+#elif defined (__mips_isa_rev) && __mips == 32
+
+static inline long long MIPS_MADD(long long acc, int a, int b) {
+ return acc + (long long)a * b;
+}
+
+static inline long long MIPS_SHILO(long long acc, int sh) {
+ return (sh >= 0) ? (acc >> sh) : (acc << -sh);
+}
+
+#define OVERRIDE_silk_warped_autocorrelation_FIX_c
+
+#endif
+
+/* Autocorrelations for a warped frequency axis */
+#if defined (OVERRIDE_silk_warped_autocorrelation_FIX_c)
+
+#undef QC
+#define QC 10
+
+#undef QS
+#define QS 14
+
+void silk_warped_autocorrelation_FIX_c(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+)
+{
+ opus_int n, i, lsh;
+ opus_int32 tmp1_QS=0, tmp2_QS=0, tmp3_QS=0, tmp4_QS=0, tmp5_QS=0, tmp6_QS=0, tmp7_QS=0, tmp8_QS=0, start_1=0, start_2=0, start_3=0;
+ opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+ opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+ opus_int64 temp64;
+
+ opus_int32 val;
+ val = 2 * QS - QC;
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+ silk_assert( 2 * QS - QC >= 0 );
+
+ /* Loop over samples */
+ for( n = 0; n < length; n=n+4 ) {
+
+ tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+ start_1 = tmp1_QS;
+ tmp3_QS = silk_LSHIFT32( (opus_int32)input[ n+1], QS );
+ start_2 = tmp3_QS;
+ tmp5_QS = silk_LSHIFT32( (opus_int32)input[ n+2], QS );
+ start_3 = tmp5_QS;
+ tmp7_QS = silk_LSHIFT32( (opus_int32)input[ n+3], QS );
+
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+ corr_QC[ i ] = MIPS_MADD( corr_QC[ i ], tmp1_QS, start_1);
+
+ tmp4_QS = silk_SMLAWB( tmp1_QS, tmp2_QS - tmp3_QS, warping_Q16 );
+ corr_QC[ i ] = MIPS_MADD( corr_QC[ i ], tmp3_QS, start_2);
+
+ tmp6_QS = silk_SMLAWB( tmp3_QS, tmp4_QS - tmp5_QS, warping_Q16 );
+ corr_QC[ i ] = MIPS_MADD( corr_QC[ i ], tmp5_QS, start_3);
+
+ tmp8_QS = silk_SMLAWB( tmp5_QS, tmp6_QS - tmp7_QS, warping_Q16 );
+ state_QS[ i ] = tmp7_QS;
+ corr_QC[ i ] = MIPS_MADD( corr_QC[ i ], tmp7_QS, state_QS[0]);
+
+ /* Output of allpass section */
+ tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+ corr_QC[ i+1 ] = MIPS_MADD( corr_QC[ i+1 ], tmp2_QS, start_1);
+
+ tmp3_QS = silk_SMLAWB( tmp2_QS, tmp1_QS - tmp4_QS, warping_Q16 );
+ corr_QC[ i+1 ] = MIPS_MADD( corr_QC[ i+1 ], tmp4_QS, start_2);
+
+ tmp5_QS = silk_SMLAWB( tmp4_QS, tmp3_QS - tmp6_QS, warping_Q16 );
+ corr_QC[ i+1 ] = MIPS_MADD( corr_QC[ i+1 ], tmp6_QS, start_3);
+
+ tmp7_QS = silk_SMLAWB( tmp6_QS, tmp5_QS - tmp8_QS, warping_Q16 );
+ state_QS[ i + 1 ] = tmp8_QS;
+ corr_QC[ i+1 ] = MIPS_MADD( corr_QC[ i+1 ], tmp8_QS, state_QS[ 0 ]);
+
+ }
+ state_QS[ order ] = tmp7_QS;
+
+ corr_QC[ order ] = MIPS_MADD( corr_QC[ order ], tmp1_QS, start_1);
+ corr_QC[ order ] = MIPS_MADD( corr_QC[ order ], tmp3_QS, start_2);
+ corr_QC[ order ] = MIPS_MADD( corr_QC[ order ], tmp5_QS, start_3);
+ corr_QC[ order ] = MIPS_MADD( corr_QC[ order ], tmp7_QS, state_QS[ 0 ]);
+ }
+
+ for(;n< length; n++ ) {
+
+ tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+
+ /* Output of allpass section */
+ tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+ state_QS[ i ] = tmp1_QS;
+ corr_QC[ i ] = MIPS_MADD( corr_QC[ i ], tmp1_QS, state_QS[ 0 ]);
+
+ /* Output of allpass section */
+ tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+ state_QS[ i + 1 ] = tmp2_QS;
+ corr_QC[ i+1 ] = MIPS_MADD( corr_QC[ i+1 ], tmp2_QS, state_QS[ 0 ]);
+ }
+ state_QS[ order ] = tmp1_QS;
+ corr_QC[ order ] = MIPS_MADD( corr_QC[ order ], tmp1_QS, state_QS[ 0 ]);
+ }
+
+ temp64 = corr_QC[ 0 ];
+ temp64 = MIPS_SHILO(temp64, val);
+
+ lsh = silk_CLZ64( temp64 ) - 35;
+ lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
+ *scale = -( QC + lsh );
+ silk_assert( *scale >= -30 && *scale <= 12 );
+ if( lsh >= 0 ) {
+ for( i = 0; i < order + 1; i++ ) {
+ temp64 = corr_QC[ i ];
+ //temp64 = MIPS_SHILO(temp64, val);
+ temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val);
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( MIPS_SHILO( temp64, -lsh ) );
+ }
+ } else {
+ for( i = 0; i < order + 1; i++ ) {
+ temp64 = corr_QC[ i ];
+ //temp64 = MIPS_SHILO(temp64, val);
+ temp64 = (val >= 0) ? (temp64 >> val) : (temp64 << -val);
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( MIPS_SHILO( temp64, -lsh ) );
+ }
+ }
+
+ corr_QC[ 0 ] = MIPS_SHILO(corr_QC[ 0 ], val);
+
+ silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
+}
+#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */
+
+#endif /* __WARPED_AUTOCORRELATION_FIX_MIPSR1_H__ */
--- /dev/null
+/***********************************************************************
+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 );
+
+ /* The additional +4 is to ensure a later vld1q_s32 call does not overflow. */
+ /* Strictly, only +3 is needed but +4 simplifies initialization using the 4x32 neon load. */
+ ALLOC( input_QST, length + 2 * MAX_SHAPE_LPC_ORDER + 4, 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 += 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 ];
+
+ /* The additional +4 is to ensure a later vld1q_s32 call does not overflow. */
+ ALLOC( state, length + order + 4, 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
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FLP_H
+#define SILK_SIGPROC_FLP_H
+
+#include "SigProc_FIX.h"
+#include "float_cast.h"
+#include "main.h"
+#include <math.h>
+
+
+/********************************************************************/
+/* SIGNAL PROCESSING FUNCTIONS */
+/********************************************************************/
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+ silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I length of ar */
+ const silk_float chirp /* I chirp factor (typically in range (0..1) ) */
+);
+
+/* compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+/* this code is based on silk_FLP_a2k() */
+silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
+ const silk_float *A, /* I prediction coefficients [order] */
+ opus_int32 order /* I prediction order */
+);
+
+silk_float silk_schur_FLP( /* O returns residual energy */
+ silk_float refl_coef[], /* O reflection coefficients (length order) */
+ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */
+ opus_int order /* I order */
+);
+
+void silk_k2a_FLP(
+ silk_float *A, /* O prediction coefficients [order] */
+ const silk_float *rc, /* I reflection coefficients [order] */
+ opus_int32 order /* I prediction order */
+);
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+ silk_float *results, /* O result (length correlationCount) */
+ const silk_float *inputData, /* I input data to correlate */
+ opus_int inputDataSize, /* I length of input */
+ opus_int correlationCount, /* I number of correlation taps to compute */
+ int arch
+);
+
+opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */
+ const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I Number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+);
+
+void silk_insertion_sort_decreasing_FLP(
+ silk_float *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP( /* O returns residual energy */
+ silk_float A[], /* O prediction coefficients (length order) */
+ const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
+ const silk_float minInvGain, /* I minimum inverse prediction gain */
+ const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I number of subframes stacked in x */
+ const opus_int D, /* I order */
+ int arch
+);
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+ silk_float *data1,
+ silk_float gain,
+ opus_int dataSize
+);
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+ silk_float *data_out,
+ const silk_float *data_in,
+ silk_float gain,
+ opus_int dataSize
+);
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP_c(
+ const silk_float *data1,
+ const silk_float *data2,
+ opus_int dataSize
+);
+
+#ifndef OVERRIDE_inner_product_FLP
+#define silk_inner_product_FLP(data1, data2, dataSize, arch) ((void)arch,silk_inner_product_FLP_c(data1, data2, dataSize))
+#endif
+
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+ const silk_float *data,
+ opus_int dataSize
+);
+
+/********************************************************************/
+/* MACROS */
+/********************************************************************/
+
+#define PI (3.1415926536f)
+
+#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b))
+#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b))
+#define silk_abs_float( a ) ((silk_float)fabs(a))
+
+/* sigmoid function */
+static OPUS_INLINE silk_float silk_sigmoid( silk_float x )
+{
+ return (silk_float)(1.0 / (1.0 + exp(-x)));
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE opus_int32 silk_float2int( silk_float x )
+{
+ return (opus_int32)float2int( x );
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE void silk_float2short_array(
+ opus_int16 *out,
+ const silk_float *in,
+ opus_int32 length
+)
+{
+ opus_int32 k;
+ for( k = length - 1; k >= 0; k-- ) {
+ out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) );
+ }
+}
+
+/* integer to floating-point conversion */
+static OPUS_INLINE void silk_short2float_array(
+ silk_float *out,
+ const opus_int16 *in,
+ opus_int32 length
+)
+{
+ opus_int32 k;
+ for( k = length - 1; k >= 0; k-- ) {
+ out[k] = (silk_float)in[k];
+ }
+}
+
+/* using log2() helps the fixed-point conversion */
+static OPUS_INLINE silk_float silk_log2( double x )
+{
+ return ( silk_float )( 3.32192809488736 * log10( x ) );
+}
+
+#endif /* SILK_SIGPROC_FLP_H */
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FLP_H
+#define SILK_MAIN_FLP_H
+
+#include "SigProc_FLP.h"
+#include "SigProc_FIX.h"
+#include "structs_FLP.h"
+#include "main.h"
+#include "define.h"
+#include "debug.h"
+#include "entenc.h"
+
+
+#define silk_encoder_state_Fxx silk_encoder_state_FLP
+#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP
+#define silk_encode_frame_Fxx silk_encode_frame_FLP
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int activity /* I Decision of Opus voice activity detector */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int32 *pnBytesOut, /* O Number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ int arch /* I Run-tim architecture */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float *pitch_res, /* I LPC residual from pitch analysis */
+ const silk_float *x /* I Input signal [frame_length + la_shape] */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+ silk_float *corr, /* O Result [order + 1] */
+ const silk_float *input, /* I Input data to correlate */
+ const silk_float warping, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/**********************************************/
+/* Prediction Analysis */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ silk_float res[], /* O Residual */
+ const silk_float x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float res_pitch[], /* I Residual from pitch analysis */
+ const silk_float x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const silk_float x[], /* I Input signal */
+ const silk_float minInvGain, /* I Prediction gain from LTP (dB) */
+ int arch
+);
+
+/* LTP analysis */
+void silk_find_LTP_FLP(
+ silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* O Weight for LTP quantization */
+ const silk_float r_ptr[], /* I LPC residual */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ int arch
+);
+
+void silk_LTP_analysis_filter_FLP(
+ silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+ const silk_float *x, /* I Input signal, with preceding samples */
+ const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int pre_length /* I Preceding samples for each subframe */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FLP(
+ silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ const silk_float x[], /* I Input signal */
+ silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const silk_float gains[], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* 16th order LPC analysis filter */
+void silk_LPC_analysis_filter_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length, /* I Length of input signal */
+ const opus_int Order /* I LPC order */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains_FLP(
+ silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */
+ opus_int8 *periodicity_index, /* O Periodicity index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ silk_float *pred_gain_dB, /* O LTP prediction gain */
+ const silk_float XX[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Correlation matrix */
+ const silk_float xX[ MAX_NB_SUBFR * LTP_ORDER ], /* I Correlation vector */
+ const opus_int subfr_len, /* I Number of samples per subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ int arch /* I Run-time architecture */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */
+ const silk_float *c, /* I Filter coefficients */
+ silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */
+ const silk_float *wXx, /* I Weighted correlation vector */
+ const silk_float wxx, /* I Weighted correlation value */
+ const opus_int D /* I Dimension */
+);
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+ const silk_float *x, /* I x vector [ L+order-1 ] used to create X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *XX, /* O X'*X correlation matrix [order x order] */
+ int arch
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+ const silk_float *x, /* I x vector [L+order-1] used to create X */
+ const silk_float *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vecors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *Xt, /* O X'*t correlation vector [order] */
+ int arch
+);
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+void silk_apply_sine_window_FLP(
+ silk_float px_win[], /* O Pointer to windowed signal */
+ const silk_float px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+);
+
+/* Wrapper functions. Call flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+ opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */
+ const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Convert NLSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+ silk_float *pAR, /* O LPC coefficients [ LPC_order ] */
+ const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
+ const opus_int LPC_order, /* I LPC order */
+ int arch /* I Run-time architecture */
+);
+
+/* Limit, stabilize, and quantize NLSFs */
+void silk_process_NLSFs_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+);
+
+/* Floating-point Silk NSQ wrapper */
+void silk_NSQ_wrapper_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ SideInfoIndices *psIndices, /* I/O Quantization indices */
+ silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const silk_float x[] /* I Prefiltered input signal */
+);
+
+#endif
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FLP_H
+#define SILK_STRUCTS_FLP_H
+
+#include "typedef.h"
+#include "main.h"
+#include "structs.h"
+
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+ opus_int8 LastGainIndex;
+ silk_float HarmShapeGain_smth;
+ silk_float Tilt_smth;
+} silk_shape_state_FLP;
+
+/********************************/
+/* Encoder state FLP */
+/********************************/
+typedef struct {
+ silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */
+ silk_shape_state_FLP sShape; /* Noise shaping state */
+
+ /* Buffer for find pitch and noise shape analysis */
+ silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+ silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */
+} silk_encoder_state_FLP;
+
+/************************/
+/* Encoder control FLP */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ silk_float Gains[ MAX_NB_SUBFR ];
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */
+ silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR];
+ silk_float LTP_scale;
+ opus_int pitchL[ MAX_NB_SUBFR ];
+
+ /* Noise shaping parameters */
+ silk_float AR[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_float LF_MA_shp[ MAX_NB_SUBFR ];
+ silk_float LF_AR_shp[ MAX_NB_SUBFR ];
+ silk_float Tilt[ MAX_NB_SUBFR ];
+ silk_float HarmShapeGain[ MAX_NB_SUBFR ];
+ silk_float Lambda;
+ silk_float input_quality;
+ silk_float coding_quality;
+
+ /* Measures */
+ silk_float predGain;
+ silk_float LTPredCodGain;
+ silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
+
+ /* Parameters for CBR mode */
+ opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
+ opus_int8 lastGainIndexPrev;
+} silk_encoder_control_FLP;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+ stereo_enc_state sStereo;
+ opus_int32 nBitsUsedLBRR;
+ opus_int32 nBitsExceeded;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int nPrevChannelsInternal;
+ opus_int timeSinceSwitchAllowed_ms;
+ opus_int allowBandwidthSwitch;
+ opus_int prev_decode_only_middle;
+ /* This needs to be last so we can skip the second state for mono. */
+ silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ];
+} silk_encoder;
+
+#endif
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef FIXED_POINT
+#include "main_FIX.h"
+#else
+#include "main_FLP.h"
+#endif
+#include "tuning_parameters.h"
+#include "cpu_support.h"
+
+#ifdef ENABLE_DRED
+#include "dred_encoder.h"
+#endif
+
+/*********************************/
+/* Initialize Silk Encoder state */
+/*********************************/
+opus_int silk_init_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int ret = 0;
+
+ /* Clear the entire encoder state */
+ silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) );
+
+ psEnc->sCmn.arch = arch;
+
+ psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 );
+ psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15;
+
+ /* Used to deactivate LSF interpolation, pitch prediction */
+ psEnc->sCmn.first_frame_after_reset = 1;
+
+ /* Initialize Silk VAD */
+ ret += silk_VAD_Init( &psEnc->sCmn.sVAD );
+
+ return ret;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+)
+{
+ opus_int i, doInterpolate;
+ opus_int NLSF_mu_Q20;
+ opus_int16 i_sqr_Q15;
+ opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ];
+ opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ];
+ opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ];
+
+ silk_assert( psEncC->speech_activity_Q8 >= 0 );
+ silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) );
+ celt_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) );
+
+ /***********************/
+ /* Calculate mu values */
+ /***********************/
+ /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */
+ NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 );
+ if( psEncC->nb_subfr == 2 ) {
+ /* Multiply by 1.5 for 10 ms packets */
+ NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 );
+ }
+
+ celt_assert( NLSF_mu_Q20 > 0 );
+ silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) );
+
+ /* Calculate NLSF weights */
+ silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder );
+
+ /* Update NLSF weights for interpolated NLSFs */
+ doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 );
+ if( doInterpolate ) {
+ /* Calculate the interpolated NLSF vector for the first half */
+ silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+ /* Calculate first half NLSF weights for the interpolated NLSFs */
+ silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+ /* Update NLSF weights with contribution from first half */
+ i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 );
+ for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+ pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT(
+ silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) );
+ silk_assert( pNLSFW_QW[ i ] >= 1 );
+ }
+ }
+
+ silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW,
+ NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType );
+
+ /* Convert quantized NLSFs back to LPC coefficients */
+ silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder, psEncC->arch );
+
+ if( doInterpolate ) {
+ /* Calculate the interpolated, quantized LSF vector for the first half */
+ silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+ /* Convert back to LPC coefficients */
+ silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder, psEncC->arch );
+
+ } else {
+ /* Copy LPC coefficients for first half from second half */
+ celt_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER );
+ silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) );
+ }
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "tuning_parameters.h"
+
+void silk_quant_LTP_gains(
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */
+ opus_int8 *periodicity_index, /* O Periodicity Index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */
+ const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */
+ const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */
+ const opus_int subfr_len, /* I Number of samples per subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int j, k, cbk_size;
+ opus_int8 temp_idx[ MAX_NB_SUBFR ];
+ const opus_uint8 *cl_ptr_Q5;
+ const opus_int8 *cbk_ptr_Q7;
+ const opus_uint8 *cbk_gain_ptr_Q7;
+ const opus_int32 *XX_Q17_ptr, *xX_Q17_ptr;
+ opus_int32 res_nrg_Q15_subfr, res_nrg_Q15, rate_dist_Q7_subfr, rate_dist_Q7, min_rate_dist_Q7;
+ opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7;
+ opus_int gain_Q7;
+
+ /***************************************************/
+ /* iterate over different codebooks with different */
+ /* rates/distortions, and choose best */
+ /***************************************************/
+ min_rate_dist_Q7 = silk_int32_MAX;
+ best_sum_log_gain_Q7 = 0;
+ for( k = 0; k < 3; k++ ) {
+ /* Safety margin for pitch gain control, to take into account factors
+ such as state rescaling/rewhitening. */
+ opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 );
+
+ cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ];
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ];
+ cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ];
+ cbk_size = silk_LTP_vq_sizes[ k ];
+
+ /* Set up pointers to first subframe */
+ XX_Q17_ptr = XX_Q17;
+ xX_Q17_ptr = xX_Q17;
+
+ res_nrg_Q15 = 0;
+ rate_dist_Q7 = 0;
+ sum_log_gain_tmp_Q7 = *sum_log_gain_Q7;
+ for( j = 0; j < nb_subfr; j++ ) {
+ max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 )
+ + SILK_FIX_CONST( 7, 7 ) ) - gain_safety;
+ silk_VQ_WMat_EC(
+ &temp_idx[ j ], /* O index of best codebook vector */
+ &res_nrg_Q15_subfr, /* O residual energy */
+ &rate_dist_Q7_subfr, /* O best weighted quantization error + mu * rate */
+ &gain_Q7, /* O sum of absolute LTP coefficients */
+ XX_Q17_ptr, /* I correlation matrix */
+ xX_Q17_ptr, /* I correlation vector */
+ cbk_ptr_Q7, /* I codebook */
+ cbk_gain_ptr_Q7, /* I codebook effective gains */
+ cl_ptr_Q5, /* I code length for each codebook vector */
+ subfr_len, /* I number of samples per subframe */
+ max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ cbk_size, /* I number of vectors in codebook */
+ arch /* I Run-time architecture */
+ );
+
+ res_nrg_Q15 = silk_ADD_POS_SAT32( res_nrg_Q15, res_nrg_Q15_subfr );
+ rate_dist_Q7 = silk_ADD_POS_SAT32( rate_dist_Q7, rate_dist_Q7_subfr );
+ sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7
+ + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 ));
+
+ XX_Q17_ptr += LTP_ORDER * LTP_ORDER;
+ xX_Q17_ptr += LTP_ORDER;
+ }
+
+ if( rate_dist_Q7 <= min_rate_dist_Q7 ) {
+ min_rate_dist_Q7 = rate_dist_Q7;
+ *periodicity_index = (opus_int8)k;
+ silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) );
+ best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7;
+ }
+ }
+
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ];
+ for( j = 0; j < nb_subfr; j++ ) {
+ for( k = 0; k < LTP_ORDER; k++ ) {
+ B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 );
+ }
+ }
+
+ if( nb_subfr == 2 ) {
+ res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 1 );
+ } else {
+ res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 2 );
+ }
+
+ *sum_log_gain_Q7 = best_sum_log_gain_Q7;
+ *pred_gain_dB_Q7 = (opus_int)silk_SMULBB( -3, silk_lin2log( res_nrg_Q15 ) - ( 15 << 7 ) );
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+#include "stack_alloc.h"
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+ stereo_enc_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */
+ opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */
+ opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */
+ opus_int32 total_rate_bps, /* I Total bitrate */
+ opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */
+ opus_int toMono, /* I Last frame before a stereo->mono transition */
+ opus_int fs_kHz, /* I Sample rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+)
+{
+ opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13;
+ opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13;
+ opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24;
+ VARDECL( opus_int16, side );
+ VARDECL( opus_int16, LP_mid );
+ VARDECL( opus_int16, HP_mid );
+ VARDECL( opus_int16, LP_side );
+ VARDECL( opus_int16, HP_side );
+ opus_int16 *mid = &x1[ -2 ];
+ SAVE_STACK;
+
+ ALLOC( side, frame_length + 2, opus_int16 );
+ /* Convert to basic mid/side signals */
+ for( n = 0; n < frame_length + 2; n++ ) {
+ sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ];
+ diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ];
+ mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+ side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) );
+ }
+
+ /* Buffering */
+ silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+ /* LP and HP filter mid signal */
+ ALLOC( LP_mid, frame_length, opus_int16 );
+ ALLOC( HP_mid, frame_length, opus_int16 );
+ for( n = 0; n < frame_length; n++ ) {
+ sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT32( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 );
+ LP_mid[ n ] = sum;
+ HP_mid[ n ] = mid[ n + 1 ] - sum;
+ }
+
+ /* LP and HP filter side signal */
+ ALLOC( LP_side, frame_length, opus_int16 );
+ ALLOC( HP_side, frame_length, opus_int16 );
+ for( n = 0; n < frame_length; n++ ) {
+ sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT32( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 );
+ LP_side[ n ] = sum;
+ HP_side[ n ] = side[ n + 1 ] - sum;
+ }
+
+ /* Find energies and predictors */
+ is10msFrame = frame_length == 10 * fs_kHz;
+ smooth_coef_Q16 = is10msFrame ?
+ SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) :
+ SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 );
+ smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 );
+
+ pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 );
+ pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 );
+ /* Ratio of the norms of residual and mid signals */
+ frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 );
+ frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) );
+
+ /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */
+ total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */
+ if( total_rate_bps < 1 ) {
+ total_rate_bps = 1;
+ }
+ min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 600 );
+ silk_assert( min_mid_rate_bps < 32767 );
+ /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */
+ frac_3_Q16 = silk_MUL( 3, frac_Q16 );
+ mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 );
+ /* If Mid bitrate below minimum, reduce stereo width */
+ if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) {
+ mid_side_rates_bps[ 0 ] = min_mid_rate_bps;
+ mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+ /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */
+ width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps,
+ silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 );
+ width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) );
+ } else {
+ mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+ width_Q14 = SILK_FIX_CONST( 1, 14 );
+ }
+
+ /* Smoother */
+ state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 );
+
+ /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */
+ *mid_only_flag = 0;
+ if( toMono ) {
+ /* Last frame before stereo->mono transition; collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ silk_stereo_quant_pred( pred_Q13, ix );
+ } else if( state->width_prev_Q14 == 0 &&
+ ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) )
+ {
+ /* Code as panned-mono; previous frame already had zero width */
+ /* Scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ /* Collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ mid_side_rates_bps[ 0 ] = total_rate_bps;
+ mid_side_rates_bps[ 1 ] = 0;
+ *mid_only_flag = 1;
+ } else if( state->width_prev_Q14 != 0 &&
+ ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) )
+ {
+ /* Transition to zero-width stereo */
+ /* Scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ /* Collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) {
+ /* Full-width stereo coding */
+ silk_stereo_quant_pred( pred_Q13, ix );
+ width_Q14 = SILK_FIX_CONST( 1, 14 );
+ } else {
+ /* Reduced-width stereo coding; scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ width_Q14 = state->smth_width_Q14;
+ }
+
+ /* Make sure to keep on encoding until the tapered output has been transmitted */
+ if( *mid_only_flag == 1 ) {
+ state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz;
+ if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) {
+ *mid_only_flag = 0;
+ } else {
+ /* Limit to avoid wrapping around */
+ state->silent_side_len = 10000;
+ }
+ } else {
+ state->silent_side_len = 0;
+ }
+
+ if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) {
+ mid_side_rates_bps[ 1 ] = 1;
+ mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]);
+ }
+
+ /* Interpolate predictors and subtract prediction from side channel */
+ pred0_Q13 = -state->pred_prev_Q13[ 0 ];
+ pred1_Q13 = -state->pred_prev_Q13[ 1 ];
+ w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 );
+ denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+ delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+ delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+ deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 );
+ for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+ pred0_Q13 += delta0_Q13;
+ pred1_Q13 += delta1_Q13;
+ w_Q24 += deltaw_Q24;
+ sum = silk_LSHIFT( silk_ADD_LSHIFT32( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+
+ pred0_Q13 = -pred_Q13[ 0 ];
+ pred1_Q13 = -pred_Q13[ 1 ];
+ w_Q24 = silk_LSHIFT( width_Q14, 10 );
+ for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+ sum = silk_LSHIFT( silk_ADD_LSHIFT32( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ];
+ state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ];
+ state->width_prev_Q14 = (opus_int16)width_Q14;
+ RESTORE_STACK;
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */
+)
+{
+ opus_int n;
+
+ /* Entropy coding */
+ n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ];
+ celt_assert( n < 25 );
+ ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 );
+ for( n = 0; n < 2; n++ ) {
+ celt_assert( ix[ n ][ 0 ] < 3 );
+ celt_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS );
+ ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 );
+ ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 );
+ }
+}
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 mid_only_flag
+)
+{
+ /* Encode flag that only mid channel is coded */
+ ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 );
+}
--- /dev/null
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "main.h"
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+ opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */
+ opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */
+)
+{
+ opus_int i, j, n;
+ opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0;
+
+ /* Quantize */
+ for( n = 0; n < 2; n++ ) {
+ /* Brute-force search over quantization levels */
+ err_min_Q13 = silk_int32_MAX;
+ for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) {
+ low_Q13 = silk_stereo_pred_quant_Q13[ i ];
+ step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13,
+ SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+ for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) {
+ lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 );
+ err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 );
+ if( err_Q13 < err_min_Q13 ) {
+ err_min_Q13 = err_Q13;
+ quant_pred_Q13 = lvl_Q13;
+ ix[ n ][ 0 ] = i;
+ ix[ n ][ 1 ] = j;
+ } else {
+ /* Error increasing, so we're past the optimum */
+ goto done;
+ }
+ }
+ }
+ done:
+ ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 );
+ ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3;
+ pred_Q13[ n ] = quant_pred_Q13;
+ }
+
+ /* Subtract second from first predictor (helps when actually applying these) */
+ pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
--- /dev/null
+/* Copyright (c) 2007-2008 CSIRO\r
+ Copyright (c) 2007-2009 Xiph.Org Foundation\r
+ Written by Jean-Marc Valin */\r
+/*\r
+ Redistribution and use in source and binary forms, with or without\r
+ modification, are permitted provided that the following conditions\r
+ are met:\r
+\r
+ - Redistributions of source code must retain the above copyright\r
+ notice, this list of conditions and the following disclaimer.\r
+\r
+ - Redistributions in binary form must reproduce the above copyright\r
+ notice, this list of conditions and the following disclaimer in the\r
+ documentation and/or other materials provided with the distribution.\r
+\r
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\r
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\r
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER\r
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdint.h>\r
+#include "opus.h"\r
+#include "opus_frame_to_pcm.h"\r
+\r
+#define MAX_PACKET_SIZE 15000\r
+#define MAX_PCM_SAMPLES 5760 /* 120ms at 48kHz */\r
+\r
+/* Encode PCM buffer to Opus packet - no file I/O */\r
+int opus_pcm_to_frame_encode_packet(const short *pcm, int pcm_samples_per_channel,\r
+ int sample_rate, int channels,\r
+ int bitrate, int application,\r
+ unsigned char *out_packet, int out_packet_max_len,\r
+ int *out_encoded_len) {\r
+ OpusEncoder *encoder = NULL;\r
+ int error = OPUS_OK;\r
+ int encoded_bytes = 0;\r
+\r
+ if (!pcm || !out_packet || out_packet_max_len <= 0 ||\r
+ pcm_samples_per_channel <= 0 || sample_rate <= 0 || channels <= 0) {\r
+ return 1;\r
+ }\r
+\r
+ encoder = opus_encoder_create(sample_rate, channels, application, &error);\r
+ if (error != OPUS_OK || !encoder) {\r
+ if (encoder) opus_encoder_destroy(encoder);\r
+ printf("[opus_pcm_to_frame] opus_encoder_create failed: %s (code=%d), rate=%d ch=%d\n",\r
+ opus_strerror(error), error, sample_rate, channels);\r
+ return 1;\r
+ }\r
+\r
+ error = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(bitrate));\r
+ if (error != OPUS_OK) {\r
+ opus_encoder_destroy(encoder);\r
+ return 1;\r
+ }\r
+ error = opus_encoder_ctl(encoder, OPUS_SET_LSB_DEPTH(16));\r
+ if (error != OPUS_OK) {\r
+ opus_encoder_destroy(encoder);\r
+ return 1;\r
+ }\r
+ opus_encoder_ctl(encoder, OPUS_RESET_STATE);\r
+\r
+ encoded_bytes = opus_encode(encoder, (const opus_int16 *)pcm, pcm_samples_per_channel,\r
+ out_packet, out_packet_max_len);\r
+ opus_encoder_destroy(encoder);\r
+\r
+ if (encoded_bytes <= 0) {\r
+ if (encoded_bytes < 0) {\r
+ printf("[opus_pcm_to_frame] opus_encode error: %s (code=%d), samples=%d, rate=%d\n",\r
+ opus_strerror(encoded_bytes), encoded_bytes, pcm_samples_per_channel, sample_rate);\r
+ }\r
+ return 1;\r
+ }\r
+ if (out_encoded_len) {\r
+ *out_encoded_len = encoded_bytes;\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* Encode PCM data to a single Opus frame file - external API */\r
+int opus_pcm_to_frame_encode_file(const char *input_file, int sample_rate, int channels,\r
+ int bitrate, int application, const char *output_file) {\r
+ OpusEncoder *encoder = NULL;\r
+ int error = OPUS_OK;\r
+ opus_int16 *pcm = NULL;\r
+ FILE *fin = NULL;\r
+ FILE *fout = NULL;\r
+ unsigned char *packet_data = NULL;\r
+ int encoded_bytes = 0;\r
+ int pcm_samples_read = 0;\r
+ \r
+ printf("=== Encoding PCM to Opus Frame ===\n");\r
+ printf("Input: %s\n", input_file);\r
+ printf("Output: %s\n", output_file ? output_file : "(stdout)");\r
+ printf("Sample rate: %d Hz, Channels: %d\n", sample_rate, channels);\r
+ printf("Bitrate: %d bps, Application: %d\n", bitrate, application);\r
+ \r
+ /* Read input file */\r
+ fin = fopen(input_file, "rb");\r
+ if (!fin) {\r
+ fprintf(stderr, "Error opening input file: %s\n", input_file);\r
+ return 1;\r
+ }\r
+ \r
+ /* Allocate buffer for PCM data */\r
+ pcm = (opus_int16*)malloc(MAX_PCM_SAMPLES * channels * sizeof(opus_int16));\r
+ if (!pcm) {\r
+ fprintf(stderr, "Error allocating PCM buffer\n");\r
+ fclose(fin);\r
+ return 1;\r
+ }\r
+ \r
+ /* Read PCM data from file */\r
+ pcm_samples_read = fread(pcm, sizeof(opus_int16), MAX_PCM_SAMPLES * channels, fin);\r
+ fclose(fin);\r
+ \r
+ if (pcm_samples_read <= 0) {\r
+ fprintf(stderr, "Error reading PCM file or file is empty\n");\r
+ free(pcm);\r
+ return 1;\r
+ }\r
+ \r
+ /* Calculate actual samples per channel */\r
+ int samples_per_channel = pcm_samples_read / channels;\r
+ if (samples_per_channel <= 0) {\r
+ fprintf(stderr, "Error: Invalid PCM data (samples per channel: %d)\n", samples_per_channel);\r
+ free(pcm);\r
+ return 1;\r
+ }\r
+ \r
+ printf("Read %d samples per channel (%d total samples)\n", samples_per_channel, pcm_samples_read);\r
+ \r
+ /* Create encoder */\r
+ encoder = opus_encoder_create(sample_rate, channels, application, &error);\r
+ if (error != OPUS_OK) {\r
+ fprintf(stderr, "Error creating encoder: %s\n", opus_strerror(error));\r
+ free(pcm);\r
+ return 1;\r
+ }\r
+ \r
+ /* Set encoder parameters */\r
+ error = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(bitrate));\r
+ if (error != OPUS_OK) {\r
+ fprintf(stderr, "Warning: Failed to set bitrate: %s\n", opus_strerror(error));\r
+ }\r
+ \r
+ /* Set LSB depth to 16 bits for 16-bit PCM input */\r
+ error = opus_encoder_ctl(encoder, OPUS_SET_LSB_DEPTH(16));\r
+ if (error != OPUS_OK) {\r
+ fprintf(stderr, "Warning: Failed to set LSB depth: %s\n", opus_strerror(error));\r
+ }\r
+ \r
+ /* Reset encoder state to ensure clean encoding */\r
+ opus_encoder_ctl(encoder, OPUS_RESET_STATE);\r
+ \r
+ /* Allocate buffer for encoded packet */\r
+ packet_data = (unsigned char*)malloc(MAX_PACKET_SIZE);\r
+ if (!packet_data) {\r
+ fprintf(stderr, "Error allocating packet buffer\n");\r
+ opus_encoder_destroy(encoder);\r
+ free(pcm);\r
+ return 1;\r
+ }\r
+ \r
+ /* Encode PCM data */\r
+ encoded_bytes = opus_encode(encoder, pcm, samples_per_channel, packet_data, MAX_PACKET_SIZE);\r
+ if (encoded_bytes <= 0) {\r
+ fprintf(stderr, "Error encoding PCM data: %s\n", opus_strerror(encoded_bytes));\r
+ opus_encoder_destroy(encoder);\r
+ free(pcm);\r
+ free(packet_data);\r
+ return 1;\r
+ }\r
+ \r
+ printf("Encoded %d bytes\n", encoded_bytes);\r
+ \r
+ /* Open output file */\r
+ if (output_file) {\r
+ fout = fopen(output_file, "wb");\r
+ if (!fout) {\r
+ fprintf(stderr, "Error opening output file: %s\n", output_file);\r
+ opus_encoder_destroy(encoder);\r
+ free(pcm);\r
+ free(packet_data);\r
+ return 1;\r
+ }\r
+ } else {\r
+ fout = stdout;\r
+ }\r
+ \r
+ /* Write encoded packet data */\r
+ if (fwrite(packet_data, 1, encoded_bytes, fout) != encoded_bytes) {\r
+ fprintf(stderr, "Error writing Opus packet data\n");\r
+ if (fout != stdout) fclose(fout);\r
+ opus_encoder_destroy(encoder);\r
+ free(pcm);\r
+ free(packet_data);\r
+ return 1;\r
+ }\r
+ \r
+ if (fout != stdout) {\r
+ fclose(fout);\r
+ printf("Saved Opus frame to: %s\n", output_file);\r
+ printf("Opus file size: %d bytes\n", encoded_bytes);\r
+ }\r
+ \r
+ /* Cleanup */\r
+ opus_encoder_destroy(encoder);\r
+ free(pcm);\r
+ free(packet_data);\r
+ \r
+ return 0;\r
+}\r
--- /dev/null
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define ANALYSIS_C
+
+#ifdef MLP_TRAINING
+#include <stdio.h>
+#endif
+
+#include "mathops.h"
+#include "kiss_fft.h"
+#include "celt.h"
+#include "modes.h"
+#include "arch.h"
+#include "quant_bands.h"
+#include "analysis.h"
+#include "mlp.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+#ifndef DISABLE_FLOAT_API
+
+#define TRANSITION_PENALTY 10
+
+static const float dct_table[128] = {
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
+ -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
+ 0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
+ -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
+ 0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
+ 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
+ 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+ 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+ 0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
+ -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
+ 0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
+ -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
+ 0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
+ 0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
+};
+
+static const float analysis_window[240] = {
+ 0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
+ 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
+ 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
+ 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
+ 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
+ 0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
+ 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
+ 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
+ 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
+ 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
+ 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
+ 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
+ 0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
+ 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
+ 0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
+ 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
+ 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
+ 0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
+ 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
+ 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
+ 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
+ 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
+ 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
+ 0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
+ 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
+ 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
+ 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
+ 0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
+ 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
+ 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
+};
+
+static const int tbands[NB_TBANDS+1] = {
+ 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 136, 160, 192, 240
+};
+
+#define NB_TONAL_SKIP_BANDS 9
+
+static opus_val32 silk_resampler_down2_hp(
+ opus_val32 *S, /* I/O State vector [ 2 ] */
+ opus_val32 *out, /* O Output signal [ floor(len/2) ] */
+ const opus_val32 *in, /* I Input signal [ len ] */
+ int inLen /* I Number of input samples */
+)
+{
+ int k, len2 = inLen/2;
+ opus_val32 in32, out32, out32_hp, Y, X;
+ opus_val64 hp_ener = 0;
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < len2; k++ ) {
+ /* Convert to Q10 */
+ in32 = in[ 2 * k ];
+
+ /* All-pass section for even input sample */
+ Y = SUB32( in32, S[ 0 ] );
+ X = MULT16_32_Q15(QCONST16(0.6074371f, 15), Y);
+ out32 = ADD32( S[ 0 ], X );
+ S[ 0 ] = ADD32( in32, X );
+ out32_hp = out32;
+ /* Convert to Q10 */
+ in32 = in[ 2 * k + 1 ];
+
+ /* All-pass section for odd input sample, and add to output of previous section */
+ Y = SUB32( in32, S[ 1 ] );
+ X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y);
+ out32 = ADD32( out32, S[ 1 ] );
+ out32 = ADD32( out32, X );
+ S[ 1 ] = ADD32( in32, X );
+
+ Y = SUB32( -in32, S[ 2 ] );
+ X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y);
+ out32_hp = ADD32( out32_hp, S[ 2 ] );
+ out32_hp = ADD32( out32_hp, X );
+ S[ 2 ] = ADD32( -in32, X );
+
+ /* len2 can be up to 480, so we shift by 8 to make it fit. */
+ hp_ener += SHR64(out32_hp*(opus_val64)out32_hp, 8);
+ /* Add, convert back to int16 and store to output */
+ out[ k ] = HALF32(out32);
+ }
+#ifdef FIXED_POINT
+ /* Fitting in 32 bits. */
+ hp_ener = hp_ener >> (2*SIG_SHIFT);
+ if (hp_ener > 2147483647) hp_ener = 2147483647;
+#endif
+ return (opus_val32)hp_ener;
+}
+
+static opus_val32 downmix_and_resample(downmix_func downmix, const void *_x, opus_val32 *y, opus_val32 S[3], int subframe, int offset, int c1, int c2, int C, int Fs)
+{
+ VARDECL(opus_val32, tmp);
+ 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;
+ }
+ else if (Fs != 24000) celt_assert(0);
+ ALLOC(tmp, subframe, opus_val32);
+
+ downmix(_x, tmp, subframe, offset, c1, c2, C);
+ if ((c2==-2 && C==2) || c2>-1) {
+ for (j=0;j<subframe;j++) {
+ tmp[j] = HALF32(tmp[j]);
+ }
+ }
+ if (Fs == 48000)
+ {
+ 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);
+ }
+ RESTORE_STACK;
+#ifndef FIXED_POINT
+ ret *= 1.f/32768/32768;
+#endif
+ return ret;
+}
+
+void tonality_analysis_init(TonalityAnalysisState *tonal, opus_int32 Fs)
+{
+ /* Initialize reusable fields. */
+ tonal->arch = opus_select_arch();
+ tonal->Fs = Fs;
+ /* Clear remaining fields. */
+ tonality_analysis_reset(tonal);
+}
+
+void tonality_analysis_reset(TonalityAnalysisState *tonal)
+{
+ /* Clear non-reusable fields. */
+ char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START;
+ OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal));
+}
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len)
+{
+ int pos;
+ int curr_lookahead;
+ float tonality_max;
+ float tonality_avg;
+ int tonality_count;
+ int i;
+ int pos0;
+ float prob_avg;
+ float prob_count;
+ float prob_min, prob_max;
+ float vad_prob;
+ int mpos, vpos;
+ int bandwidth_span;
+
+ pos = tonal->read_pos;
+ curr_lookahead = tonal->write_pos-tonal->read_pos;
+ if (curr_lookahead<0)
+ curr_lookahead += DETECT_SIZE;
+
+ tonal->read_subframe += len/(tonal->Fs/400);
+ while (tonal->read_subframe>=8)
+ {
+ tonal->read_subframe -= 8;
+ tonal->read_pos++;
+ }
+ if (tonal->read_pos>=DETECT_SIZE)
+ tonal->read_pos-=DETECT_SIZE;
+
+ /* On long frames, look at the second analysis window rather than the first. */
+ if (len > tonal->Fs/50 && pos != tonal->write_pos)
+ {
+ pos++;
+ if (pos==DETECT_SIZE)
+ pos=0;
+ }
+ if (pos == tonal->write_pos)
+ pos--;
+ if (pos<0)
+ pos = DETECT_SIZE-1;
+ pos0 = pos;
+ OPUS_COPY(info_out, &tonal->info[pos], 1);
+ if (!info_out->valid)
+ return;
+ tonality_max = tonality_avg = info_out->tonality;
+ tonality_count = 1;
+ /* Look at the neighbouring frames and pick largest bandwidth found (to be safe). */
+ bandwidth_span = 6;
+ /* If possible, look ahead for a tone to compensate for the delay in the tone detector. */
+ for (i=0;i<3;i++)
+ {
+ pos++;
+ if (pos==DETECT_SIZE)
+ pos = 0;
+ if (pos == tonal->write_pos)
+ break;
+ tonality_max = MAX32(tonality_max, tonal->info[pos].tonality);
+ tonality_avg += tonal->info[pos].tonality;
+ tonality_count++;
+ info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth);
+ bandwidth_span--;
+ }
+ pos = pos0;
+ /* Look back in time to see if any has a wider bandwidth than the current frame. */
+ for (i=0;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)
+ {
+ 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);
+ }
+ 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) ((1.f/32768/32768)*e)
+#endif
+
+#ifdef FIXED_POINT
+static int is_digital_silence32(const opus_val32* pcm, int frame_size, int channels, int lsb_depth)
+{
+ int silence = 0;
+ opus_val32 sample_max = 0;
+#ifdef MLP_TRAINING
+ return 0;
+#endif
+ sample_max = celt_maxabs32(pcm, frame_size*channels);
+
+ silence = (sample_max == 0);
+ (void)lsb_depth;
+ return silence;
+}
+#else
+#define is_digital_silence32(pcm, frame_size, channels, lsb_depth) is_digital_silence(pcm, frame_size, channels, lsb_depth)
+#endif
+
+static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix)
+{
+ int i, b;
+ const kiss_fft_state *kfft;
+ VARDECL(kiss_fft_cpx, in);
+ VARDECL(kiss_fft_cpx, out);
+ int N = 480, N2=240;
+ float * OPUS_RESTRICT A = tonal->angle;
+ float * OPUS_RESTRICT dA = tonal->d_angle;
+ float * OPUS_RESTRICT d2A = tonal->d2_angle;
+ VARDECL(float, tonality);
+ VARDECL(float, noisiness);
+ float band_tonality[NB_TBANDS];
+ float logE[NB_TBANDS];
+ float BFCC[8];
+ float features[25];
+ float frame_tonality;
+ float max_frame_tonality;
+ /*float tw_sum=0;*/
+ float frame_noisiness;
+ const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI);
+ float slope=0;
+ float frame_stationarity;
+ float relativeE;
+ float frame_probs[2];
+ float alpha, alphaE, alphaE2;
+ float frame_loudness;
+ float bandwidth_mask;
+ int is_masked[NB_TBANDS+1];
+ int bandwidth=0;
+ float maxE = 0;
+ float noise_floor;
+ int remaining;
+ AnalysisInfo *info;
+ float hp_ener;
+ float tonality2[240];
+ float midE[8];
+ float spec_variability=0;
+ float band_log2[NB_TBANDS+1];
+ float leakage_from[NB_TBANDS+1];
+ float leakage_to[NB_TBANDS+1];
+ float layer_out[MAX_NEURONS];
+ float below_max_pitch;
+ float above_max_pitch;
+ int is_silence;
+ SAVE_STACK;
+
+ if (!tonal->initialized)
+ {
+ tonal->mem_fill = 240;
+ tonal->initialized = 1;
+ }
+ alpha = 1.f/IMIN(10, 1+tonal->count);
+ alphaE = 1.f/IMIN(25, 1+tonal->count);
+ /* Noise floor related decay for bandwidth detection: -2.2 dB/second */
+ alphaE2 = 1.f/IMIN(100, 1+tonal->count);
+ if (tonal->count <= 1) alphaE2 = 1;
+
+ if (tonal->Fs == 48000)
+ {
+ /* len and offset are now at 24 kHz. */
+ len/= 2;
+ offset /= 2;
+ } else if (tonal->Fs == 16000) {
+ len = 3*len/2;
+ offset = 3*offset/2;
+ }
+
+ kfft = celt_mode->mdct.kfft[0];
+ tonal->hp_ener_accum += (float)downmix_and_resample(downmix, x,
+ &tonal->inmem[tonal->mem_fill], tonal->downmix_state,
+ IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C, tonal->Fs);
+ if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
+ {
+ tonal->mem_fill += len;
+ /* Don't have enough to update the analysis */
+ RESTORE_STACK;
+ return;
+ }
+ hp_ener = tonal->hp_ener_accum;
+ info = &tonal->info[tonal->write_pos++];
+ if (tonal->write_pos>=DETECT_SIZE)
+ tonal->write_pos-=DETECT_SIZE;
+
+ is_silence = is_digital_silence32(tonal->inmem, ANALYSIS_BUF_SIZE, 1, lsb_depth);
+
+ ALLOC(in, 480, kiss_fft_cpx);
+ ALLOC(out, 480, kiss_fft_cpx);
+ ALLOC(tonality, 240, float);
+ ALLOC(noisiness, 240, float);
+ for (i=0;i<N2;i++)
+ {
+ float w = analysis_window[i];
+ in[i].r = (kiss_fft_scalar)(w*tonal->inmem[i]);
+ in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]);
+ in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]);
+ in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]);
+ }
+ OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
+ remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
+ tonal->hp_ener_accum = (float)downmix_and_resample(downmix, x,
+ &tonal->inmem[240], tonal->downmix_state, remaining,
+ offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C, tonal->Fs);
+ tonal->mem_fill = 240 + remaining;
+ if (is_silence)
+ {
+ /* On silence, copy the previous analysis. */
+ int prev_pos = tonal->write_pos-2;
+ if (prev_pos < 0)
+ prev_pos += DETECT_SIZE;
+ OPUS_COPY(info, &tonal->info[prev_pos], 1);
+ RESTORE_STACK;
+ return;
+ }
+ opus_fft(kfft, in, out, tonal->arch);
+#ifndef FIXED_POINT
+ /* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */
+ if (celt_isnan(out[0].r))
+ {
+ info->valid = 0;
+ RESTORE_STACK;
+ return;
+ }
+#endif
+
+ for (i=1;i<N2;i++)
+ {
+ float X1r, X2r, X1i, X2i;
+ float angle, d_angle, d2_angle;
+ float angle2, d_angle2, d2_angle2;
+ float mod1, mod2, avg_mod;
+ X1r = (float)out[i].r+out[N-i].r;
+ X1i = (float)out[i].i-out[N-i].i;
+ X2r = (float)out[i].i+out[N-i].i;
+ X2i = (float)out[N-i].r-out[i].r;
+
+ angle = (float)(.5f/M_PI)*fast_atan2f(X1i, X1r);
+ d_angle = angle - A[i];
+ d2_angle = d_angle - dA[i];
+
+ angle2 = (float)(.5f/M_PI)*fast_atan2f(X2i, X2r);
+ d_angle2 = angle2 - angle;
+ d2_angle2 = d_angle2 - d_angle;
+
+ mod1 = d2_angle - (float)float2int(d2_angle);
+ noisiness[i] = ABS16(mod1);
+ mod1 *= mod1;
+ mod1 *= mod1;
+
+ mod2 = d2_angle2 - (float)float2int(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. */
+ 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;*/
+ info->activity = 0;
+ frame_noisiness = 0;
+ frame_stationarity = 0;
+ if (!tonal->count)
+ {
+ for (b=0;b<NB_TBANDS;b++)
+ {
+ tonal->lowE[b] = 1e10;
+ tonal->highE[b] = -1e10;
+ }
+ }
+ relativeE = 0;
+ frame_loudness = 0;
+ /* The energy of the very first band is special because of DC. */
+ {
+ float E = 0;
+ float X1r, X2r;
+ X1r = 2*(float)out[0].r;
+ X2r = 2*(float)out[0].i;
+ E = X1r*X1r + X2r*X2r;
+ for (i=1;i<4;i++)
+ {
+ float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+ + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+ E += binE;
+ }
+ E = SCALE_ENER(E);
+ band_log2[0] = .5f*1.442695f*(float)log(E+1e-10f);
+ }
+ for (b=0;b<NB_TBANDS;b++)
+ {
+ float E=0, tE=0, nE=0;
+ float L1, L2;
+ float stationarity;
+ for (i=tbands[b];i<tbands[b+1];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;
+ binE = SCALE_ENER(binE);
+ E += binE;
+ tE += binE*MAX32(0, tonality[i]);
+ nE += binE*2.f*(.5f-noisiness[i]);
+ }
+#ifndef FIXED_POINT
+ /* Check for extreme band energies that could cause NaNs later. */
+ if (!(E<1e9f) || celt_isnan(E))
+ {
+ info->valid = 0;
+ RESTORE_STACK;
+ return;
+ }
+#endif
+
+ tonal->E[tonal->E_count][b] = E;
+ frame_noisiness += nE/(1e-15f+E);
+
+ frame_loudness += (float)sqrt(E+1e-10f);
+ logE[b] = (float)log(E+1e-10f);
+ band_log2[b+1] = .5f*1.442695f*(float)log(E+1e-10f);
+ tonal->logE[tonal->E_count][b] = logE[b];
+ if (tonal->count==0)
+ tonal->highE[b] = tonal->lowE[b] = logE[b];
+ if (tonal->highE[b] > tonal->lowE[b] + 7.5)
+ {
+ if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b])
+ tonal->highE[b] -= .01f;
+ else
+ tonal->lowE[b] += .01f;
+ }
+ if (logE[b] > tonal->highE[b])
+ {
+ tonal->highE[b] = logE[b];
+ tonal->lowE[b] = MAX32(tonal->highE[b]-15, tonal->lowE[b]);
+ } else if (logE[b] < tonal->lowE[b])
+ {
+ tonal->lowE[b] = logE[b];
+ tonal->highE[b] = MIN32(tonal->lowE[b]+15, tonal->highE[b]);
+ }
+ relativeE += (logE[b]-tonal->lowE[b])/(1e-5f + (tonal->highE[b]-tonal->lowE[b]));
+
+ L1=L2=0;
+ for (i=0;i<NB_FRAMES;i++)
+ {
+ L1 += (float)sqrt(tonal->E[i][b]);
+ L2 += tonal->E[i][b];
+ }
+
+ stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2));
+ stationarity *= stationarity;
+ stationarity *= stationarity;
+ frame_stationarity += stationarity;
+ /*band_tonality[b] = tE/(1e-15+E)*/;
+ band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]);
+#if 0
+ if (b>=NB_TONAL_SKIP_BANDS)
+ {
+ frame_tonality += tweight[b]*band_tonality[b];
+ tw_sum += tweight[b];
+ }
+#else
+ frame_tonality += band_tonality[b];
+ if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS)
+ frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS];
+#endif
+ max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality);
+ slope += band_tonality[b]*(b-8);
+ /*printf("%f %f ", band_tonality[b], stationarity);*/
+ tonal->prev_band_tonality[b] = band_tonality[b];
+ }
+
+ leakage_from[0] = band_log2[0];
+ leakage_to[0] = band_log2[0] - LEAKAGE_OFFSET;
+ for (b=1;b<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)));
+ noise_floor *= noise_floor;
+ below_max_pitch=0;
+ above_max_pitch=0;
+ for (b=0;b<NB_TBANDS;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];
+ 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]);
+ /* Consider the band "active" only if all these conditions are met:
+ 1) less than 90 dB below the peak band (maximal masking possible considering
+ both the ATH and the loudness-dependent slope of the spreading function)
+ 2) above the PCM quantization noise floor
+ We use b+1 because the first CELT band isn't included in tbands[]
+ */
+ if (E*1e9f > maxE && (Em > 3*noise_floor*(band_end-band_start) || E > noise_floor*(band_end-band_start)))
+ bandwidth = b+1;
+ /* Check if the band is masked (see below). */
+ is_masked[b] = E < (tonal->prev_bandwidth >= b+1 ? .01f : .05f)*bandwidth_mask;
+ /* Use a simple follower with 13 dB/Bark slope for spreading function. */
+ bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
+ }
+ /* Special case for the last two bands, for which we don't have spectrum but only
+ the energy above 12 kHz. The difficulty here is that the high-pass we use
+ leaks some LF energy, so we need to increase the threshold without accidentally cutting
+ off the band. */
+ if (tonal->Fs == 48000) {
+ float noise_ratio;
+ float Em;
+ float E = hp_ener*(1.f/(60*60));
+ noise_ratio = tonal->prev_bandwidth==20 ? 10.f : 30.f;
+
+#ifdef FIXED_POINT
+ /* silk_resampler_down2_hp() shifted right by an extra 8 bits. */
+ E *= 256.f*(1.f/Q15ONE)*(1.f/Q15ONE);
+#endif
+ above_max_pitch += E;
+ tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
+ Em = MAX32(E, tonal->meanE[b]);
+ if (Em > 3*noise_ratio*noise_floor*160 || E > noise_ratio*noise_floor*160)
+ bandwidth = 20;
+ /* Check if the band is masked (see below). */
+ is_masked[b] = E < (tonal->prev_bandwidth == 20 ? .01f : .05f)*bandwidth_mask;
+ }
+ if (above_max_pitch > below_max_pitch)
+ info->max_pitch_ratio = below_max_pitch/above_max_pitch;
+ else
+ info->max_pitch_ratio = 1;
+ /* In some cases, resampling aliasing can create a small amount of energy in the first band
+ being cut. So if the last band is masked, we don't include it. */
+ if (bandwidth == 20 && is_masked[NB_TBANDS])
+ bandwidth-=2;
+ else if (bandwidth > 0 && bandwidth <= NB_TBANDS && is_masked[bandwidth-1])
+ bandwidth--;
+ if (tonal->count<=2)
+ bandwidth = 20;
+ frame_loudness = 20*(float)log10(frame_loudness);
+ tonal->Etracker = MAX32(tonal->Etracker-.003f, frame_loudness);
+ tonal->lowECount *= (1-alphaE);
+ if (frame_loudness < tonal->Etracker-30)
+ tonal->lowECount += alphaE;
+
+ for (i=0;i<8;i++)
+ {
+ float sum=0;
+ for (b=0;b<16;b++)
+ sum += dct_table[i*16+b]*logE[b];
+ BFCC[i] = sum;
+ }
+ for (i=0;i<8;i++)
+ {
+ float sum=0;
+ for (b=0;b<16;b++)
+ sum += dct_table[i*16+b]*.5f*(tonal->highE[b]+tonal->lowE[b]);
+ midE[i] = sum;
+ }
+
+ frame_stationarity /= NB_TBANDS;
+ relativeE /= NB_TBANDS;
+ if (tonal->count<10)
+ relativeE = .5f;
+ frame_noisiness /= NB_TBANDS;
+#if 1
+ info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
+#else
+ info->activity = .5*(1+frame_noisiness-frame_stationarity);
+#endif
+ frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS));
+ frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f);
+ tonal->prev_tonality = frame_tonality;
+
+ slope /= 8*8;
+ info->tonality_slope = slope;
+
+ tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
+ tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX);
+ info->tonality = frame_tonality;
+
+ for (i=0;i<4;i++)
+ features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i];
+
+ for (i=0;i<4;i++)
+ tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i];
+
+ for (i=0;i<4;i++)
+ features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]);
+ for (i=0;i<3;i++)
+ features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8];
+
+ if (tonal->count > 5)
+ {
+ for (i=0;i<9;i++)
+ tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i];
+ }
+ for (i=0;i<4;i++)
+ features[i] = BFCC[i]-midE[i];
+
+ for (i=0;i<8;i++)
+ {
+ tonal->mem[i+24] = tonal->mem[i+16];
+ tonal->mem[i+16] = tonal->mem[i+8];
+ tonal->mem[i+8] = tonal->mem[i];
+ tonal->mem[i] = BFCC[i];
+ }
+ for (i=0;i<9;i++)
+ features[11+i] = (float)sqrt(tonal->std[i]) - std_feature_bias[i];
+ features[18] = spec_variability - 0.78f;
+ features[20] = info->tonality - 0.154723f;
+ features[21] = info->activity - 0.724643f;
+ features[22] = frame_stationarity - 0.743717f;
+ features[23] = info->tonality_slope + 0.069216f;
+ features[24] = tonal->lowECount - 0.067930f;
+
+ analysis_compute_dense(&layer0, layer_out, features);
+ analysis_compute_gru(&layer1, tonal->rnn_state, layer_out);
+ analysis_compute_dense(&layer2, frame_probs, tonal->rnn_state);
+
+ /* Probability of speech or music vs noise */
+ info->activity_probability = frame_probs[1];
+ info->music_prob = frame_probs[0];
+
+ /*printf("%f %f %f\n", frame_probs[0], frame_probs[1], info->music_prob);*/
+#ifdef MLP_TRAINING
+ for (i=0;i<25;i++)
+ printf("%f ", features[i]);
+ printf("\n");
+#endif
+
+ info->bandwidth = bandwidth;
+ tonal->prev_bandwidth = bandwidth;
+ /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
+ info->noisiness = frame_noisiness;
+ info->valid = 1;
+ RESTORE_STACK;
+}
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+ int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+ int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
+{
+ int offset;
+ int pcm_len;
+
+ analysis_frame_size -= analysis_frame_size&1;
+ if (analysis_pcm != NULL)
+ {
+ /* Avoid overflow/wrap-around of the analysis buffer */
+ analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/50, analysis_frame_size);
+
+ pcm_len = analysis_frame_size - analysis->analysis_offset;
+ offset = analysis->analysis_offset;
+ while (pcm_len>0) {
+ tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(Fs/50, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
+ offset += Fs/50;
+ pcm_len -= Fs/50;
+ }
+ analysis->analysis_offset = analysis_frame_size;
+
+ analysis->analysis_offset -= frame_size;
+ }
+
+ tonality_get_info(analysis, analysis_info, frame_size);
+}
+
+#endif /* DISABLE_FLOAT_API */
--- /dev/null
+/* Copyright (c) 2008-2011 Octasic Inc.
+ 2012-2017 Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include "opus_types.h"
+#include "opus_defines.h"
+#include "arch.h"
+#include "mlp.h"
+
+#define fmadd(a, b, c) ((a)*(b)+(c))
+static OPUS_INLINE float tansig_approx(float x)
+{
+ const float N0 = 952.52801514f;
+ const float N1 = 96.39235687f;
+ const float N2 = 0.60863042f;
+ const float D0 = 952.72399902f;
+ const float D1 = 413.36801147f;
+ const float D2 = 11.88600922f;
+ float X2, num, den;
+ X2 = x*x;
+ num = fmadd(fmadd(N2, X2, N1), X2, N0);
+ den = fmadd(fmadd(D2, X2, D1), X2, D0);
+ num = num*x/den;
+ return MAX32(-1.f, MIN32(1.f, num));
+}
+
+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 analysis_compute_dense(const AnalysisDenseLayer *layer, float *output, const float *input)
+{
+ 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]);
+ }
+}
+
+void analysis_compute_gru(const AnalysisGRULayer *gru, float *state, const float *input)
+{
+ 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];
+}
--- /dev/null
+/*This file is automatically generated from a Keras model*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#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
+};
+
+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 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
+};
+
+static const opus_int8 layer2_bias[2] = {
+ 14, 117
+};
+
+const AnalysisDenseLayer layer0 = {
+ layer0_bias,
+ layer0_weights,
+ 25, 32, 0
+};
+
+const AnalysisGRULayer layer1 = {
+ layer1_bias,
+ layer1_weights,
+ layer1_recur_weights,
+ 32, 24
+};
+
+const AnalysisDenseLayer layer2 = {
+ layer2_bias,
+ layer2_weights,
+ 24, 2, 1
+};
--- /dev/null
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include "celt.h"
+#include "entenc.h"
+#include "modes.h"
+#include "API.h"
+#include "stack_alloc.h"
+#include "float_cast.h"
+#include "opus.h"
+#include "arch.h"
+#include "pitch.h"
+#include "opus_private.h"
+#include "os_support.h"
+#include "cpu_support.h"
+#include "analysis.h"
+#include "mathops.h"
+#include "tuning_parameters.h"
+
+#ifdef ENABLE_DRED
+#include "dred_coding.h"
+#endif
+
+#ifdef FIXED_POINT
+#include "fixed/structs_FIX.h"
+#else
+#include "float/structs_FLP.h"
+#endif
+#ifdef ENABLE_OSCE_TRAINING_DATA
+#include <stdio.h>
+#endif
+
+#ifdef ENABLE_QEXT
+#define MAX_ENCODER_BUFFER 960
+#else
+#define MAX_ENCODER_BUFFER 480
+#endif
+
+#define PSEUDO_SNR_THRESHOLD 316.23f /* 10^(25/10) */
+
+typedef struct {
+ opus_val32 XX, XY, YY;
+ opus_val16 smoothed_width;
+ opus_val16 max_follower;
+} StereoWidthState;
+
+struct OpusEncoder {
+ int celt_enc_offset;
+ int silk_enc_offset;
+ silk_EncControlStruct silk_mode;
+#ifdef ENABLE_DRED
+ DREDEnc dred_encoder;
+#endif
+ int application;
+ int channels;
+ int delay_compensation;
+ int force_channels;
+ int signal_type;
+ int user_bandwidth;
+ int max_bandwidth;
+ int user_forced_mode;
+ int voice_ratio;
+ opus_int32 Fs;
+ int use_vbr;
+ int vbr_constraint;
+ int variable_duration;
+ opus_int32 bitrate_bps;
+ opus_int32 user_bitrate_bps;
+ int lsb_depth;
+ int encoder_buffer;
+ int lfe;
+ int arch;
+ int use_dtx; /* general DTX for both SILK and CELT */
+ int fec_config;
+#ifndef DISABLE_FLOAT_API
+ TonalityAnalysisState analysis;
+#endif
+#ifdef ENABLE_QEXT
+ int enable_qext;
+#endif
+
+#define OPUS_ENCODER_RESET_START stream_channels
+ int stream_channels;
+ opus_int16 hybrid_stereo_width_Q14;
+ opus_int32 variable_HP_smth2_Q15;
+ opus_val16 prev_HB_gain;
+ opus_val32 hp_mem[4];
+ int mode;
+ int prev_mode;
+ int prev_channels;
+ int prev_framesize;
+ int bandwidth;
+ /* Bandwidth determined automatically from the rate (before any other adjustment) */
+ int auto_bandwidth;
+ int silk_bw_switch;
+ /* Sampling rate (at the API level) */
+ int first;
+ celt_glog * energy_masking;
+ StereoWidthState width_mem;
+#ifndef DISABLE_FLOAT_API
+ int detected_bandwidth;
+#endif
+ int nb_no_activity_ms_Q1;
+ opus_val32 peak_signal_energy;
+#ifdef ENABLE_DRED
+ int dred_duration;
+ int dred_q0;
+ int dred_dQ;
+ int dred_qmax;
+ int dred_target_chunks;
+ unsigned char activity_mem[DRED_MAX_FRAMES*4]; /* 2.5ms resolution*/
+#endif
+ int nonfinal_frame; /* current frame is not the final in a packet */
+ opus_uint32 rangeFinal;
+ /* Needs to be the last field because it may be partially or completely omitted. */
+ opus_res delay_buffer[MAX_ENCODER_BUFFER*2];
+};
+
+/* Transition tables for the voice and music. First column is the
+ middle (memoriless) threshold. The second column is the hysteresis
+ (difference with the middle) */
+static const opus_int32 mono_voice_bandwidth_thresholds[8] = {
+ 9000, 700, /* NB<->MB */
+ 9000, 700, /* MB<->WB */
+ 13500, 1000, /* WB<->SWB */
+ 14000, 2000, /* SWB<->FB */
+};
+static const opus_int32 mono_music_bandwidth_thresholds[8] = {
+ 9000, 700, /* NB<->MB */
+ 9000, 700, /* MB<->WB */
+ 11000, 1000, /* WB<->SWB */
+ 12000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_voice_bandwidth_thresholds[8] = {
+ 9000, 700, /* NB<->MB */
+ 9000, 700, /* MB<->WB */
+ 13500, 1000, /* WB<->SWB */
+ 14000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_music_bandwidth_thresholds[8] = {
+ 9000, 700, /* NB<->MB */
+ 9000, 700, /* MB<->WB */
+ 11000, 1000, /* WB<->SWB */
+ 12000, 2000, /* SWB<->FB */
+};
+/* Threshold bit-rates for switching between mono and stereo */
+static const opus_int32 stereo_voice_threshold = 19000;
+static const opus_int32 stereo_music_threshold = 17000;
+
+/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */
+static const opus_int32 mode_thresholds[2][2] = {
+ /* voice */ /* music */
+ { 64000, 10000}, /* mono */
+ { 44000, 10000}, /* stereo */
+};
+
+static const opus_int32 fec_thresholds[] = {
+ 12000, 1000, /* NB */
+ 14000, 1000, /* MB */
+ 16000, 1000, /* WB */
+ 20000, 1000, /* SWB */
+ 22000, 1000, /* FB */
+};
+
+int opus_encoder_get_size(int channels)
+{
+ int ret;
+ ret = opus_encoder_init(NULL, 48000, channels, OPUS_APPLICATION_AUDIO);
+ if (ret < 0)
+ return 0;
+ else
+ return ret;
+}
+
+int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application)
+{
+ void *silk_enc=NULL;
+ CELTEncoder *celt_enc=NULL;
+ int err;
+ int ret, silkEncSizeBytes, celtEncSizeBytes=0;
+ int tot_size;
+ int base_size;
+
+ if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000
+#ifdef ENABLE_QEXT
+ &&Fs!=96000
+#endif
+ )||(channels!=1&&channels!=2)||
+ (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+ && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ && application != OPUS_APPLICATION_RESTRICTED_SILK
+ && application != OPUS_APPLICATION_RESTRICTED_CELT))
+ return OPUS_BAD_ARG;
+
+ /* Create SILK encoder */
+ ret = silk_Get_Encoder_Size( &silkEncSizeBytes, channels );
+ if (ret)
+ return OPUS_BAD_ARG;
+ silkEncSizeBytes = align(silkEncSizeBytes);
+ if (application == OPUS_APPLICATION_RESTRICTED_CELT)
+ silkEncSizeBytes = 0;
+ if (application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celtEncSizeBytes = celt_encoder_get_size(channels);
+ base_size = align(sizeof(OpusEncoder));
+ if (application == OPUS_APPLICATION_RESTRICTED_SILK || application == OPUS_APPLICATION_RESTRICTED_CELT) {
+ base_size = align(base_size - MAX_ENCODER_BUFFER*2*sizeof(opus_res));
+ } else if (channels==1)
+ base_size = align(base_size - MAX_ENCODER_BUFFER*sizeof(opus_res));
+ tot_size = base_size+silkEncSizeBytes+celtEncSizeBytes;
+ if (st == NULL) {
+ return tot_size;
+ }
+ OPUS_CLEAR((char*)st, tot_size);
+ st->silk_enc_offset = base_size;
+ st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes;
+
+ st->stream_channels = st->channels = channels;
+
+ st->Fs = Fs;
+
+ st->arch = opus_select_arch();
+
+ if (application != OPUS_APPLICATION_RESTRICTED_CELT)
+ {
+ silk_enc = (char*)st+st->silk_enc_offset;
+ ret = silk_InitEncoder( silk_enc, st->channels, st->arch, &st->silk_mode );
+ }
+ if(ret)return OPUS_INTERNAL_ERROR;
+
+ /* default SILK parameters */
+ st->silk_mode.nChannelsAPI = channels;
+ st->silk_mode.nChannelsInternal = channels;
+ st->silk_mode.API_sampleRate = st->Fs;
+ st->silk_mode.maxInternalSampleRate = 16000;
+ st->silk_mode.minInternalSampleRate = 8000;
+ st->silk_mode.desiredInternalSampleRate = 16000;
+ st->silk_mode.payloadSize_ms = 20;
+ st->silk_mode.bitRate = 25000;
+ st->silk_mode.packetLossPercentage = 0;
+ st->silk_mode.complexity = 9;
+ st->silk_mode.useInBandFEC = 0;
+ st->silk_mode.useDRED = 0;
+ st->silk_mode.useDTX = 0;
+ st->silk_mode.useCBR = 0;
+ st->silk_mode.reducedDependency = 0;
+
+ /* Create CELT encoder */
+ /* Initialize CELT encoder */
+ if (application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+ err = celt_encoder_init(celt_enc, Fs, channels, st->arch);
+ if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+ celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity));
+ }
+
+#ifdef ENABLE_DRED
+ /* Initialize DRED Encoder */
+ dred_encoder_init( &st->dred_encoder, Fs, channels );
+#endif
+
+ st->use_vbr = 1;
+ /* Makes constrained VBR the default (safer for real-time use) */
+ st->vbr_constraint = 1;
+ st->user_bitrate_bps = OPUS_AUTO;
+ st->bitrate_bps = 3000+Fs*channels;
+ st->application = application;
+ st->signal_type = OPUS_AUTO;
+ st->user_bandwidth = OPUS_AUTO;
+ st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ st->force_channels = OPUS_AUTO;
+ st->user_forced_mode = OPUS_AUTO;
+ st->voice_ratio = -1;
+ if (application != OPUS_APPLICATION_RESTRICTED_CELT && application != OPUS_APPLICATION_RESTRICTED_SILK)
+ st->encoder_buffer = st->Fs/100;
+ else
+ st->encoder_buffer = 0;
+ st->lsb_depth = 24;
+ st->variable_duration = OPUS_FRAMESIZE_ARG;
+
+ /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead
+ + 1.5 ms for SILK resamplers and stereo prediction) */
+ st->delay_compensation = st->Fs/250;
+
+ st->hybrid_stereo_width_Q14 = 1 << 14;
+ st->prev_HB_gain = Q15ONE;
+ st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ st->first = 1;
+ st->mode = MODE_HYBRID;
+ st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+#ifndef DISABLE_FLOAT_API
+ tonality_analysis_init(&st->analysis, st->Fs);
+ st->analysis.application = st->application;
+#endif
+
+ return OPUS_OK;
+}
+
+static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels)
+{
+ int period;
+ unsigned char toc;
+ period = 0;
+ while (framerate < 400)
+ {
+ framerate <<= 1;
+ period++;
+ }
+ if (mode == MODE_SILK_ONLY)
+ {
+ toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5;
+ toc |= (period-2)<<3;
+ } else if (mode == MODE_CELT_ONLY)
+ {
+ int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND;
+ if (tmp < 0)
+ tmp = 0;
+ toc = 0x80;
+ toc |= tmp << 5;
+ toc |= period<<3;
+ } else /* Hybrid */
+ {
+ toc = 0x60;
+ toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4;
+ toc |= (period-2)<<3;
+ }
+ toc |= (channels==2)<<2;
+ return toc;
+}
+
+#ifdef FIXED_POINT
+/* Second order ARMA filter, alternative implementation */
+void silk_biquad_res(
+ const opus_res *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_res *out, /* O output signal */
+ const opus_int32 len, /* I signal length (must be even) */
+ int stride
+)
+{
+ /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+ opus_int k;
+ opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
+
+ /* Negate A_Q28 values and split in two parts */
+ A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */
+ A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */
+ A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */
+ A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */
+
+ for( k = 0; k < len; k++ ) {
+ /* S[ 0 ], S[ 1 ]: Q12 */
+ inval = RES2INT16(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 );
+ S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 );
+ S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval);
+
+ S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 );
+ S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 );
+ S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval );
+
+ /* Scale back to Q0 and saturate */
+ out[ k*stride ] = INT16TORES( silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ) );
+ }
+}
+#else
+static void silk_biquad_res(
+ const opus_res *in, /* I: Input signal */
+ const opus_int32 *B_Q28, /* I: MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I: AR coefficients [2] */
+ opus_val32 *S, /* I/O: State vector [2] */
+ opus_res *out, /* O: Output signal */
+ const opus_int32 len, /* I: Signal length (must be even) */
+ int stride
+)
+{
+ /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+ opus_int k;
+ opus_val32 vout;
+ opus_val32 inval;
+ opus_val32 A[2], B[3];
+
+ A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28)));
+ A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28)));
+ B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28)));
+ B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28)));
+ B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28)));
+
+ /* Negate A_Q28 values and split in two parts */
+
+ for( k = 0; k < len; k++ ) {
+ /* S[ 0 ], S[ 1 ]: Q12 */
+ inval = in[ k*stride ];
+ vout = S[ 0 ] + B[0]*inval;
+
+ S[ 0 ] = S[1] - vout*A[0] + B[1]*inval;
+
+ S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL;
+
+ /* Scale back to Q0 and saturate */
+ out[ k*stride ] = vout;
+ }
+}
+#endif
+
+static void hp_cutoff(const opus_res *in, opus_int32 cutoff_Hz, opus_res *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs, int arch)
+{
+ opus_int32 B_Q28[ 3 ], A_Q28[ 2 ];
+ opus_int32 Fc_Q19, r_Q28, r_Q22;
+ (void)arch;
+
+ silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) );
+ Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 );
+ silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 );
+
+ r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 );
+
+ /* b = r * [ 1; -2; 1 ]; */
+ /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
+ B_Q28[ 0 ] = r_Q28;
+ B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 );
+ B_Q28[ 2 ] = r_Q28;
+
+ /* -r * ( 2 - Fc * Fc ); */
+ r_Q22 = silk_RSHIFT( r_Q28, 6 );
+ A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) );
+ A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 );
+
+#if defined(FIXED_POINT) && !defined(ENABLE_RES24)
+ if( channels == 1 ) {
+ silk_biquad_alt_stride1( in, B_Q28, A_Q28, hp_mem, out, len );
+ } else {
+ silk_biquad_alt_stride2( in, B_Q28, A_Q28, hp_mem, out, len, arch );
+ }
+#else
+ silk_biquad_res( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+ if( channels == 2 ) {
+ silk_biquad_res( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+ }
+#endif
+}
+
+#ifdef FIXED_POINT
+static void dc_reject(const opus_res *in, opus_int32 cutoff_Hz, opus_res *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ int c, i;
+ int shift;
+
+ /* Approximates -round(log2(6.3*cutoff_Hz/Fs)) */
+ shift=celt_ilog2(Fs/(cutoff_Hz*4));
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x, y;
+ /* Saturate at +6 dBFS to avoid any wrap-around. */
+ x = SATURATE((opus_val32)in[channels*i+c], (1<<16<<RES_SHIFT)-1);
+ x = SHL32(x, 14-RES_SHIFT);
+ y = x-hp_mem[2*c];
+ hp_mem[2*c] = hp_mem[2*c] + PSHR32(x - hp_mem[2*c], shift);
+#ifdef ENABLE_RES24
+ /* Don't saturate if we have the headroom to avoid it. */
+ out[channels*i+c] = PSHR32(y, 14-RES_SHIFT);
+#else
+ out[channels*i+c] = SATURATE(PSHR32(y, 14-RES_SHIFT), 32767);
+#endif
+ }
+ }
+}
+
+#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)
+ {
+ 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;
+ }
+ 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
+
+static void stereo_fade(const opus_res *in, opus_res *out, opus_val16 g1, opus_val16 g2,
+ int overlap48, int frame_size, int channels, const celt_coef *window, opus_int32 Fs)
+{
+ int i;
+ int overlap;
+ int inc;
+ inc = IMAX(1, 48000/Fs);
+ overlap=overlap48/inc;
+ g1 = Q15ONE-g1;
+ g2 = Q15ONE-g2;
+ for (i=0;i<overlap;i++)
+ {
+ opus_val32 diff;
+ opus_val16 g, w;
+ w = COEF2VAL16(window[i*inc]);
+ w = MULT16_16_Q15(w, w);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ diff = HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]);
+ diff = MULT16_RES_Q15(g, diff);
+ out[i*channels] = out[i*channels] - diff;
+ out[i*channels+1] = out[i*channels+1] + diff;
+ }
+ for (;i<frame_size;i++)
+ {
+ opus_val32 diff;
+ diff = HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]);
+ diff = MULT16_RES_Q15(g2, diff);
+ out[i*channels] = out[i*channels] - diff;
+ out[i*channels+1] = out[i*channels+1] + diff;
+ }
+}
+
+static void gain_fade(const opus_res *in, opus_res *out, opus_val16 g1, opus_val16 g2,
+ int overlap48, int frame_size, int channels, const celt_coef *window, opus_int32 Fs)
+{
+ int i;
+ int inc;
+ int overlap;
+ int c;
+ inc = IMAX(1, 48000/Fs);
+ overlap=overlap48/inc;
+ if (channels==1)
+ {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 g, w;
+ w = COEF2VAL16(window[i*inc]);
+ w = MULT16_16_Q15(w, w);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ out[i] = MULT16_RES_Q15(g, in[i]);
+ }
+ } else {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 g, w;
+ w = COEF2VAL16(window[i*inc]);
+ w = MULT16_16_Q15(w, w);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ out[i*2] = MULT16_RES_Q15(g, in[i*2]);
+ out[i*2+1] = MULT16_RES_Q15(g, in[i*2+1]);
+ }
+ }
+ c=0;do {
+ for (i=overlap;i<frame_size;i++)
+ {
+ out[i*channels+c] = MULT16_RES_Q15(g2, in[i*channels+c]);
+ }
+ }
+ while (++c<channels);
+}
+
+OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
+{
+ int ret;
+ OpusEncoder *st;
+ int size;
+ if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000
+#ifdef ENABLE_QEXT
+ &&Fs!=96000
+#endif
+ )||(channels!=1&&channels!=2)||
+ (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+ && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ && application != OPUS_APPLICATION_RESTRICTED_SILK
+ && application != OPUS_APPLICATION_RESTRICTED_CELT))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ size = opus_encoder_init(NULL, Fs, channels, application);
+ if (size <= 0)
+ {
+ if (error)
+ *error = OPUS_INTERNAL_ERROR;
+ return NULL;
+ }
+ st = (OpusEncoder *)opus_alloc(size);
+ if (st == NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_encoder_init(st, Fs, channels, application);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+#ifdef ENABLE_DRED
+
+static const float dred_bits_table[16] = {73.2f, 68.1f, 62.5f, 57.0f, 51.5f, 45.7f, 39.9f, 32.4f, 26.4f, 20.4f, 16.3f, 13.f, 9.3f, 8.2f, 7.2f, 6.4f};
+static int estimate_dred_bitrate(int q0, int dQ, int qmax, int duration, opus_int32 target_bits, int *target_chunks) {
+ int dred_chunks;
+ int i;
+ float bits;
+ /* Signaling DRED costs 3 bytes. */
+ bits = 8*(3+DRED_EXPERIMENTAL_BYTES);
+ /* Approximation for the size of the IS. */
+ bits += 50.f+dred_bits_table[q0];
+ dred_chunks = IMIN((duration+5)/4, DRED_NUM_REDUNDANCY_FRAMES/2);
+ if (target_chunks != NULL) *target_chunks = 0;
+ for (i=0;i<dred_chunks;i++) {
+ int q = compute_quantizer(q0, dQ, qmax, i);
+ bits += dred_bits_table[q];
+ if (target_chunks != NULL && bits < target_bits) *target_chunks = i+1;
+ }
+ return (int)floor(.5f+bits);
+}
+
+static opus_int32 compute_dred_bitrate(OpusEncoder *st, opus_int32 bitrate_bps, int frame_size)
+{
+ float dred_frac;
+ int bitrate_offset;
+ opus_int32 dred_bitrate;
+ opus_int32 target_dred_bitrate;
+ int target_chunks;
+ opus_int32 max_dred_bits;
+ int q0, dQ, qmax;
+ if (st->silk_mode.useInBandFEC) {
+ dred_frac = MIN16(.7f, 3.f*st->silk_mode.packetLossPercentage/100.f);
+ bitrate_offset = 20000;
+ } else {
+ if (st->silk_mode.packetLossPercentage > 5) {
+ dred_frac = MIN16(.8f, .55f + st->silk_mode.packetLossPercentage/100.f);
+ } else {
+ dred_frac = 12*st->silk_mode.packetLossPercentage/100.f;
+ }
+ bitrate_offset = 12000;
+ }
+ /* Account for the fact that longer packets require less redundancy. */
+ dred_frac = dred_frac/(dred_frac + (1-dred_frac)*(frame_size*50.f)/st->Fs);
+ /* Approximate fit based on a few experiments. Could probably be improved. */
+ q0 = IMIN(15, IMAX(4, 51 - 3*EC_ILOG(IMAX(1, bitrate_bps-bitrate_offset))));
+ dQ = bitrate_bps-bitrate_offset > 36000 ? 3 : 5;
+ qmax = 15;
+ target_dred_bitrate = IMAX(0, (int)(dred_frac*(bitrate_bps-bitrate_offset)));
+ if (st->dred_duration > 0) {
+ opus_int32 target_bits = bitrate_to_bits(target_dred_bitrate, st->Fs, frame_size);
+ max_dred_bits = estimate_dred_bitrate(q0, dQ, qmax, st->dred_duration, target_bits, &target_chunks);
+ } else {
+ max_dred_bits = 0;
+ target_chunks=0;
+ }
+ dred_bitrate = IMIN(target_dred_bitrate, bits_to_bitrate(max_dred_bits, st->Fs, frame_size));
+ /* If we can't afford enough bits, don't bother with DRED at all. */
+ if (target_chunks < 2)
+ dred_bitrate = 0;
+ st->dred_q0 = q0;
+ st->dred_dQ = dQ;
+ st->dred_qmax = qmax;
+ st->dred_target_chunks = target_chunks;
+ return dred_bitrate;
+}
+#endif
+
+static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int max_data_bytes)
+{
+ opus_int32 max_bitrate, user_bitrate;
+ if(!frame_size)frame_size=st->Fs/400;
+ max_bitrate = bits_to_bitrate(max_data_bytes*8, st->Fs, frame_size);
+ if (st->user_bitrate_bps==OPUS_AUTO)
+ user_bitrate = 60*st->Fs/frame_size + st->Fs*st->channels;
+ else if (st->user_bitrate_bps==OPUS_BITRATE_MAX)
+ user_bitrate = 1500000;
+ else
+ user_bitrate = st->user_bitrate_bps;
+ return IMIN(user_bitrate, max_bitrate);
+}
+
+#ifndef DISABLE_FLOAT_API
+void downmix_float(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C)
+{
+ const float *x;
+ int j;
+
+ x = (const float *)_x;
+ for (j=0;j<subframe;j++)
+ y[j] = FLOAT2SIG(x[(j+offset)*C+c1]);
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ y[j] += FLOAT2SIG(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] += FLOAT2SIG(x[(j+offset)*C+c]);
+ }
+ }
+#ifndef FIXED_POINT
+ /* Cap signal to +6 dBFS to avoid problems in the analysis. */
+ for (j=0;j<subframe;j++)
+ {
+ if (y[j] < -65536.f) y[j] = -65536.f;
+ if (y[j] > 65536.f) y[j] = 65536.f;
+ if (celt_isnan(y[j])) y[j] = 0;
+ }
+#endif
+}
+#endif
+
+void downmix_int(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C)
+{
+ const opus_int16 *x;
+ int j;
+
+ x = (const opus_int16 *)_x;
+ for (j=0;j<subframe;j++)
+ y[j] = INT16TOSIG(x[(j+offset)*C+c1]);
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ y[j] += INT16TOSIG(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] += INT16TOSIG(x[(j+offset)*C+c]);
+ }
+ }
+}
+
+void downmix_int24(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C)
+{
+ const opus_int32 *x;
+ int j;
+
+ x = (const opus_int32 *)_x;
+ for (j=0;j<subframe;j++)
+ y[j] = INT24TOSIG(x[(j+offset)*C+c1]);
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ y[j] += INT24TOSIG(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] += INT24TOSIG(x[(j+offset)*C+c]);
+ }
+ }
+}
+
+opus_int32 frame_size_select(int application, opus_int32 frame_size, int variable_duration, opus_int32 Fs)
+{
+ int new_size;
+ if (frame_size<Fs/400)
+ 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
+ return -1;
+ if (new_size>frame_size)
+ return -1;
+ if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs &&
+ 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs &&
+ 50*new_size!=4*Fs && 50*new_size!=5*Fs && 50*new_size!=6*Fs)
+ return -1;
+ if (application == OPUS_APPLICATION_RESTRICTED_SILK && new_size < Fs/100)
+ return -1;
+ return new_size;
+}
+
+opus_val16 compute_stereo_width(const opus_res *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem)
+{
+ opus_val32 xx, xy, yy;
+ opus_val16 sqrt_xx, sqrt_yy;
+ opus_val16 qrrt_xx, qrrt_yy;
+ int frame_rate;
+ int i;
+ opus_val16 short_alpha;
+#ifdef FIXED_POINT
+ int shift = celt_ilog2(frame_size)-2;
+#endif
+ frame_rate = Fs/frame_size;
+ short_alpha = MULT16_16(25, Q15ONE)/IMAX(50,frame_rate);
+ xx=xy=yy=0;
+ /* Unroll by 4. The frame size is always a multiple of 4 *except* for
+ 2.5 ms frames at 12 kHz. Since this setting is very rare (and very
+ stupid), we just discard the last two samples. */
+ for (i=0;i<frame_size-3;i+=4)
+ {
+ opus_val32 pxx=0;
+ opus_val32 pxy=0;
+ opus_val32 pyy=0;
+ opus_val16 x, y;
+ x = RES2VAL16(pcm[2*i]);
+ y = RES2VAL16(pcm[2*i+1]);
+ pxx = SHR32(MULT16_16(x,x),2);
+ pxy = SHR32(MULT16_16(x,y),2);
+ pyy = SHR32(MULT16_16(y,y),2);
+ x = RES2VAL16(pcm[2*i+2]);
+ y = RES2VAL16(pcm[2*i+3]);
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+ x = RES2VAL16(pcm[2*i+4]);
+ y = RES2VAL16(pcm[2*i+5]);
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+ x = RES2VAL16(pcm[2*i+6]);
+ y = RES2VAL16(pcm[2*i+7]);
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+
+ xx += SHR32(pxx, shift);
+ xy += SHR32(pxy, shift);
+ yy += SHR32(pyy, shift);
+ }
+#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);*/
+ /* Rewritten to avoid overflows on abrupt sign change. */
+ mem->XY = MULT16_32_Q15(Q15ONE - short_alpha, mem->XY) + MULT16_32_Q15(short_alpha, xy);
+ mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY);
+ mem->XX = MAX32(0, mem->XX);
+ mem->XY = MAX32(0, mem->XY);
+ mem->YY = MAX32(0, mem->YY);
+ if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18))
+ {
+ opus_val16 corr;
+ opus_val16 ldiff;
+ opus_val16 width;
+ sqrt_xx = celt_sqrt(mem->XX);
+ sqrt_yy = celt_sqrt(mem->YY);
+ qrrt_xx = celt_sqrt(sqrt_xx);
+ qrrt_yy = celt_sqrt(sqrt_yy);
+ /* Inter-channel correlation */
+ mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy);
+ corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16);
+ /* Approximate loudness difference */
+ ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy);
+ width = MULT16_16_Q15(MIN16(Q15ONE, celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr))), ldiff);
+ /* Smoothing over one second */
+ mem->smoothed_width += (width-mem->smoothed_width)/frame_rate;
+ /* Peak follower */
+ mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width);
+ }
+ /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/
+ return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower)));
+}
+
+static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate)
+{
+ int orig_bandwidth;
+ if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY)
+ return 0;
+ orig_bandwidth = *bandwidth;
+ for (;;)
+ {
+ opus_int32 hysteresis;
+ opus_int32 LBRR_rate_thres_bps;
+ /* Compute threshold for using FEC at the current bandwidth setting */
+ LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)];
+ hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1];
+ if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis;
+ if (last_fec == 0) LBRR_rate_thres_bps += hysteresis;
+ LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps,
+ 125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
+ /* If loss <= 5%, we look at whether we have enough rate to enable FEC.
+ If loss > 5%, we decrease the bandwidth until we can enable FEC. */
+ if (rate > LBRR_rate_thres_bps)
+ return 1;
+ else if (PacketLoss_perc <= 5)
+ return 0;
+ else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND)
+ (*bandwidth)--;
+ else
+ break;
+ }
+ /* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */
+ *bandwidth = orig_bandwidth;
+ return 0;
+}
+
+static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr, int fec, int channels) {
+ int entry;
+ int i;
+ int N;
+ int silk_rate;
+ static const 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;
+}
+
+int is_digital_silence(const opus_res* 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_maxabs_res(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_res *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 = RES2INT16(celt_maxabs_res(pcm, len));
+
+ /* Compute the right shift required in the MAC to avoid an overflow */
+ max_shift = celt_ilog2(len);
+ shift = IMAX(0, (celt_ilog2(1+sample_max) << 1) + max_shift - 28);
+
+ /* Compute the energy */
+ for (i=0; i<len; i++)
+ energy += SHR32(MULT16_16(RES2INT16(pcm[i]), RES2INT16(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(opus_int activity, /* indicates if this frame contains speech/music */
+ int *nb_no_activity_ms_Q1, /* number of consecutive milliseconds with no activity, in Q1 */
+ int frame_size_ms_Q1 /* number of milliseconds in this update, in Q1 */
+ )
+
+{
+ if (!activity)
+ {
+ /* The number of consecutive DTX frames should be within the allowed bounds.
+ Note that the allowed bound is defined in the SILK headers and assumes 20 ms
+ frames. As this function can be called with any frame length, a conversion to
+ milliseconds is done before the comparisons. */
+ (*nb_no_activity_ms_Q1) += frame_size_ms_Q1;
+ if (*nb_no_activity_ms_Q1 > NB_SPEECH_FRAMES_BEFORE_DTX*20*2)
+ {
+ if (*nb_no_activity_ms_Q1 <= (NB_SPEECH_FRAMES_BEFORE_DTX + MAX_CONSECUTIVE_DTX)*20*2)
+ /* Valid frame for DTX! */
+ return 1;
+ else
+ (*nb_no_activity_ms_Q1) = NB_SPEECH_FRAMES_BEFORE_DTX*20*2;
+ }
+ } else
+ (*nb_no_activity_ms_Q1) = 0;
+
+ return 0;
+}
+
+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;
+}
+
+static opus_int32 opus_encode_frame_native(OpusEncoder *st, const opus_res *pcm, int frame_size,
+ unsigned char *data, opus_int32 max_data_bytes,
+ int float_api, int first_frame,
+#ifdef ENABLE_DRED
+ opus_int32 dred_bitrate_bps,
+#endif
+#ifndef DISABLE_FLOAT_API
+ AnalysisInfo *analysis_info,
+#endif
+ int is_silence, int redundancy, int celt_to_silk, int prefill,
+ opus_int32 equiv_rate, int to_celt);
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_res *pcm, int frame_size,
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+ const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2,
+ int analysis_channels, downmix_func downmix, int float_api)
+{
+ void *silk_enc=NULL;
+ CELTEncoder *celt_enc=NULL;
+ int i;
+ int ret=0;
+ int prefill=0;
+ int redundancy = 0;
+ int celt_to_silk = 0;
+ int to_celt = 0;
+ int voice_est; /* Probability of voice in Q7 */
+ opus_int32 equiv_rate;
+ int frame_rate;
+ opus_int32 max_rate; /* Max bitrate we're allowed to use */
+ int curr_bandwidth;
+ opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
+ opus_int32 cbr_bytes=-1;
+ opus_val16 stereo_width;
+ const CELTMode *celt_mode=NULL;
+ int packet_size_cap = 1276;
+#ifndef DISABLE_FLOAT_API
+ AnalysisInfo analysis_info;
+ int analysis_read_pos_bak=-1;
+ int analysis_read_subframe_bak=-1;
+#endif
+ int is_silence = 0;
+#ifdef ENABLE_DRED
+ opus_int32 dred_bitrate_bps;
+#endif
+ ALLOC_STACK;
+
+#ifdef ENABLE_QEXT
+ if (st->enable_qext) packet_size_cap = QEXT_PACKET_SIZE_CAP;
+#endif
+
+ /* Just avoid insane packet sizes here, but the real bounds are applied later on. */
+ max_data_bytes = IMIN(packet_size_cap*6, out_data_bytes);
+
+ st->rangeFinal = 0;
+ if (frame_size <= 0 || max_data_bytes <= 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ /* Cannot encode 100 ms in 1 byte */
+ if (max_data_bytes==1 && st->Fs==(frame_size*10))
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+
+ if (st->application != OPUS_APPLICATION_RESTRICTED_CELT)
+ silk_enc = (char*)st+st->silk_enc_offset;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+ lsb_depth = IMIN(lsb_depth, st->lsb_depth);
+
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
+ is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth);
+#ifndef DISABLE_FLOAT_API
+ analysis_info.valid = 0;
+#ifdef FIXED_POINT
+ if (st->silk_mode.complexity >= 10 && st->Fs>=16000 && st->Fs<=48000 && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+#else
+ if (st->silk_mode.complexity >= 7 && st->Fs>=16000 && st->Fs<=48000 && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+#endif
+ {
+ 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);
+
+ } 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
+
+ /* 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;
+#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));
+ }
+
+ analysis_bandwidth = analysis_info.bandwidth;
+ if (analysis_bandwidth<=12)
+ st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (analysis_bandwidth<=14)
+ st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (analysis_bandwidth<=16)
+ st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (analysis_bandwidth<=18)
+ st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else
+ st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ }
+#else
+ st->voice_ratio = -1;
+#endif
+
+ /* Track the peak signal energy */
+#ifndef DISABLE_FLOAT_API
+ if (!analysis_info.valid || analysis_info.activity_probability > DTX_ACTIVITY_THRESHOLD)
+#endif
+ {
+ if (!is_silence)
+ {
+ 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));
+ }
+ }
+ if (st->channels==2 && st->force_channels!=1)
+ stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem);
+ else
+ stereo_width = 0;
+ st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes);
+
+ frame_rate = st->Fs/frame_size;
+ if (!st->use_vbr)
+ {
+ cbr_bytes = IMIN((bitrate_to_bits(st->bitrate_bps, st->Fs, frame_size)+4)/8, max_data_bytes);
+ st->bitrate_bps = bits_to_bitrate(cbr_bytes*8, st->Fs, frame_size);
+ /* Make sure we provide at least one byte to avoid failing. */
+ max_data_bytes = IMAX(1, cbr_bytes);
+ }
+#ifdef ENABLE_DRED
+ /* Allocate some of the bits to DRED if needed. */
+ dred_bitrate_bps = compute_dred_bitrate(st, st->bitrate_bps, frame_size);
+ st->bitrate_bps -= dred_bitrate_bps;
+#endif
+ if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8
+ || (frame_rate<50 && (max_data_bytes*(opus_int32)frame_rate<300 || st->bitrate_bps < 2400)))
+ {
+ /*If the space is too low to do something useful, emit 'PLC' frames.*/
+ int tocmode = st->mode;
+ int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth;
+ int packet_code = 0;
+ int num_multiframes = 0;
+
+ if (tocmode==0)
+ tocmode = MODE_SILK_ONLY;
+ if (frame_rate>100)
+ tocmode = MODE_CELT_ONLY;
+ /* 40 ms -> 2 x 20 ms if in CELT_ONLY or HYBRID mode */
+ if (frame_rate==25 && tocmode!=MODE_SILK_ONLY)
+ {
+ frame_rate = 50;
+ packet_code = 1;
+ }
+
+ /* >= 60 ms frames */
+ if (frame_rate<=16)
+ {
+ /* 1 x 60 ms, 2 x 40 ms, 2 x 60 ms */
+ if (out_data_bytes==1 || (tocmode==MODE_SILK_ONLY && frame_rate!=10))
+ {
+ tocmode = MODE_SILK_ONLY;
+
+ packet_code = frame_rate <= 12;
+ frame_rate = frame_rate == 12 ? 25 : 16;
+ }
+ else
+ {
+ num_multiframes = 50/frame_rate;
+ frame_rate = 50;
+ packet_code = 3;
+ }
+ }
+
+ if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND)
+ bw=OPUS_BANDWIDTH_WIDEBAND;
+ else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND)
+ bw=OPUS_BANDWIDTH_NARROWBAND;
+ else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND)
+ bw=OPUS_BANDWIDTH_SUPERWIDEBAND;
+
+ data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels);
+ data[0] |= packet_code;
+
+ ret = packet_code <= 1 ? 1 : 2;
+
+ max_data_bytes = IMAX(max_data_bytes, ret);
+
+ if (packet_code==3)
+ data[1] = num_multiframes;
+
+ if (!st->use_vbr)
+ {
+ ret = opus_packet_pad(data, ret, max_data_bytes);
+ if (ret == OPUS_OK)
+ ret = max_data_bytes;
+ else
+ ret = OPUS_INTERNAL_ERROR;
+ }
+ RESTORE_STACK;
+ return ret;
+ }
+ max_rate = bits_to_bitrate(max_data_bytes*8, st->Fs, frame_size);
+
+ /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
+ equiv_rate = compute_equiv_rate(st->bitrate_bps, st->channels, st->Fs/frame_size,
+ st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage);
+
+ if (st->signal_type == OPUS_SIGNAL_VOICE)
+ voice_est = 127;
+ else if (st->signal_type == OPUS_SIGNAL_MUSIC)
+ voice_est = 0;
+ else if (st->voice_ratio >= 0)
+ {
+ voice_est = st->voice_ratio*327>>8;
+ /* For AUDIO, never be more than 90% confident of having speech */
+ if (st->application == OPUS_APPLICATION_AUDIO)
+ voice_est = IMIN(voice_est, 115);
+ } else if (st->application == OPUS_APPLICATION_VOIP)
+ voice_est = 115;
+ else
+ voice_est = 48;
+
+ if (st->force_channels!=OPUS_AUTO && st->channels == 2)
+ {
+ st->stream_channels = st->force_channels;
+ } else {
+#ifdef FUZZING
+ (void)stereo_music_threshold;
+ (void)stereo_voice_threshold;
+ /* Random mono/stereo decision */
+ if (st->channels == 2 && (rand()&0x1F)==0)
+ st->stream_channels = 3-st->stream_channels;
+#else
+ /* Rate-dependent mono-stereo decision */
+ if (st->channels == 2)
+ {
+ opus_int32 stereo_threshold;
+ stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14);
+ if (st->stream_channels == 2)
+ stereo_threshold -= 1000;
+ else
+ stereo_threshold += 1000;
+ st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1;
+ } else {
+ st->stream_channels = st->channels;
+ }
+#endif
+ }
+ /* Update equivalent rate for channels decision. */
+ equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size,
+ st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage);
+
+ /* Allow SILK DTX if DTX is enabled but the generalized DTX cannot be used,
+ e.g. because of the complexity setting or sample rate. */
+#ifndef DISABLE_FLOAT_API
+ st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence);
+#else
+ st->silk_mode.useDTX = st->use_dtx && !is_silence;
+#endif
+
+ /* Mode selection depending on application and signal type */
+ if (st->application == OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ st->mode = MODE_SILK_ONLY;
+ } else if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY || st->application == OPUS_APPLICATION_RESTRICTED_CELT)
+ {
+ st->mode = MODE_CELT_ONLY;
+ } else if (st->user_forced_mode == OPUS_AUTO)
+ {
+#ifdef FUZZING
+ (void)stereo_width;
+ (void)mode_thresholds;
+ /* Random mode switching */
+ if ((rand()&0xF)==0)
+ {
+ if ((rand()&0x1)==0)
+ st->mode = MODE_CELT_ONLY;
+ else
+ st->mode = MODE_SILK_ONLY;
+ } else {
+ if (st->prev_mode==MODE_CELT_ONLY)
+ st->mode = MODE_CELT_ONLY;
+ else
+ st->mode = MODE_SILK_ONLY;
+ }
+#else
+ opus_int32 mode_voice, mode_music;
+ opus_int32 threshold;
+
+ /* Interpolate based on stereo width */
+ mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0])
+ + MULT16_32_Q15(stereo_width,mode_thresholds[1][0]));
+ mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1])
+ + MULT16_32_Q15(stereo_width,mode_thresholds[1][1]));
+ /* Interpolate based on speech/music probability */
+ threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14);
+ /* Bias towards SILK for VoIP because of some useful features */
+ if (st->application == OPUS_APPLICATION_VOIP)
+ threshold += 8000;
+
+ /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/
+ /* Hysteresis */
+ if (st->prev_mode == MODE_CELT_ONLY)
+ threshold -= 4000;
+ else if (st->prev_mode>0)
+ threshold += 4000;
+
+ st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY;
+
+ /* When FEC is enabled and there's enough packet loss, use SILK.
+ Unless the FEC is set to 2, in which case we don't switch to SILK if we're confident we have music. */
+ if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4 && (st->fec_config != 2 || voice_est > 25))
+ st->mode = MODE_SILK_ONLY;
+ /* When encoding voice and DTX is enabled but the generalized DTX cannot be used,
+ use SILK in order to make use of its DTX. */
+ if (st->silk_mode.useDTX && voice_est > 100)
+ st->mode = MODE_SILK_ONLY;
+#endif
+
+ /* If max_data_bytes represents less than 6 kb/s, switch to CELT-only mode */
+ if (max_data_bytes < bitrate_to_bits(frame_rate > 50 ? 9000 : 6000, st->Fs, frame_size)/8)
+ st->mode = MODE_CELT_ONLY;
+ } else {
+ st->mode = st->user_forced_mode;
+ }
+
+ /* Override the chosen mode to make sure we meet the requested frame size */
+ if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100)
+ {
+ celt_assert(st->application != OPUS_APPLICATION_RESTRICTED_SILK);
+ st->mode = MODE_CELT_ONLY;
+ }
+ if (st->lfe && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ st->mode = MODE_CELT_ONLY;
+
+ if (st->prev_mode > 0 &&
+ ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ||
+ (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)))
+ {
+ redundancy = 1;
+ celt_to_silk = (st->mode != MODE_CELT_ONLY);
+ if (!celt_to_silk)
+ {
+ /* Switch to SILK/hybrid if frame size is 10 ms or more*/
+ if (frame_size >= st->Fs/100)
+ {
+ st->mode = st->prev_mode;
+ to_celt = 1;
+ } else {
+ redundancy=0;
+ }
+ }
+ }
+
+ /* When encoding multiframes, we can ask for a switch to CELT only in the last frame. This switch
+ * is processed above as the requested mode shouldn't interrupt stereo->mono transition. */
+ if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0
+ && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)
+ {
+ /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */
+ st->silk_mode.toMono = 1;
+ st->stream_channels = 2;
+ } else {
+ st->silk_mode.toMono = 0;
+ }
+
+ /* Update equivalent rate with mode decision. */
+ equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size,
+ st->use_vbr, st->mode, st->silk_mode.complexity, st->silk_mode.packetLossPercentage);
+
+ if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY)
+ {
+ silk_EncControlStruct dummy;
+ silk_InitEncoder( silk_enc, st->channels, st->arch, &dummy);
+ prefill=1;
+ }
+
+ /* Automatic (rate-dependent) bandwidth selection */
+ if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch)
+ {
+ const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds;
+ opus_int32 bandwidth_thresholds[8];
+ int bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+ if (st->channels==2 && st->force_channels!=1)
+ {
+ voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = stereo_music_bandwidth_thresholds;
+ } else {
+ voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = mono_music_bandwidth_thresholds;
+ }
+ /* Interpolate bandwidth thresholds depending on voice estimation */
+ for (i=0;i<8;i++)
+ {
+ bandwidth_thresholds[i] = music_bandwidth_thresholds[i]
+ + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14);
+ }
+ do {
+ int threshold, hysteresis;
+ threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)];
+ hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1];
+ if (!st->first)
+ {
+ if (st->auto_bandwidth >= bandwidth)
+ threshold -= hysteresis;
+ else
+ threshold += hysteresis;
+ }
+ if (equiv_rate >= threshold)
+ break;
+ } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND);
+ /* We don't use mediumband anymore, except when explicitly requested or during
+ mode transitions. */
+ if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ st->bandwidth = st->auto_bandwidth = bandwidth;
+ /* Prevents any transition to SWB/FB until the SILK layer has fully
+ switched to WB mode and turned the variable LP filter off */
+ if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ }
+
+ if (st->bandwidth>st->max_bandwidth)
+ st->bandwidth = st->max_bandwidth;
+
+ if (st->user_bandwidth != OPUS_AUTO)
+ st->bandwidth = st->user_bandwidth;
+
+ /* This prevents us from using hybrid at unsafe CBR/max rates */
+ if (st->mode != MODE_CELT_ONLY && max_rate < 15000)
+ {
+ st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND);
+ }
+
+ /* Prevents Opus from wasting bits on frequencies that are above
+ the Nyquist rate of the input signal */
+ if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND)
+ st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
+ st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+#ifndef DISABLE_FLOAT_API
+ /* Use detected bandwidth to reduce the encoded bandwidth. */
+ if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO)
+ {
+ int min_detected_bandwidth;
+ /* Makes bandwidth detection more conservative just in case the detector
+ gets it wrong when we could have coded a high bandwidth transparently.
+ When operating in SILK/hybrid mode, we don't go below wideband to avoid
+ more complicated switches that require redundancy. */
+ if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+ min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+ min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (equiv_rate <= 30000*st->stream_channels)
+ min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (equiv_rate <= 44000*st->stream_channels)
+ min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else
+ min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+ st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth);
+ st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
+ }
+#endif
+ st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage,
+ st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate);
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
+
+ /* CELT mode doesn't support mediumband, use wideband instead */
+ if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ if (st->lfe)
+ st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+
+ curr_bandwidth = st->bandwidth;
+
+ if (st->application == OPUS_APPLICATION_RESTRICTED_SILK && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ /* Chooses the appropriate mode for speech
+ *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */
+ if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->mode = MODE_HYBRID;
+ if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND)
+ st->mode = MODE_SILK_ONLY;
+
+ /* Can't support higher than >60 ms frames, and >20 ms when in Hybrid or CELT-only modes */
+ if ((frame_size > st->Fs/50 && (st->mode != MODE_SILK_ONLY)) || frame_size > 3*st->Fs/50)
+ {
+ int enc_frame_size;
+ int nb_frames;
+ VARDECL(unsigned char, tmp_data);
+ VARDECL(OpusRepacketizer, rp);
+ int max_header_bytes;
+ opus_int32 repacketize_len;
+ opus_int32 max_len_sum;
+ opus_int32 tot_size=0;
+ unsigned char *curr_data;
+ int tmp_len;
+ int dtx_count = 0;
+ int bak_to_mono;
+
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ if (frame_size == 2*st->Fs/25) /* 80 ms -> 2x 40 ms */
+ enc_frame_size = st->Fs/25;
+ else if (frame_size == 3*st->Fs/25) /* 120 ms -> 2x 60 ms */
+ enc_frame_size = 3*st->Fs/50;
+ else /* 100 ms -> 5x 20 ms */
+ enc_frame_size = st->Fs/50;
+ }
+ else
+ enc_frame_size = st->Fs/50;
+
+ nb_frames = frame_size/enc_frame_size;
+
+#ifndef DISABLE_FLOAT_API
+ if (analysis_read_pos_bak!= -1)
+ {
+ /* Reset analysis position to the beginning of the first frame so we
+ can use it one frame at a time. */
+ st->analysis.read_pos = analysis_read_pos_bak;
+ st->analysis.read_subframe = analysis_read_subframe_bak;
+ }
+#endif
+
+ /* 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);
+#ifdef ENABLE_QEXT
+ /* Cover the use of the separators that are the only thing that can get us over
+ once we consider that we need to subtract the extension overhead in each
+ of the individual frames. Also consider that a separator can get our padding
+ from 254 to 255, which costs an extra length byte (at most once). */
+ if (st->enable_qext) max_header_bytes += (nb_frames-1) + 1;
+#endif
+
+ if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX)
+ repacketize_len = out_data_bytes;
+ else {
+ celt_assert(cbr_bytes>=0);
+ repacketize_len = IMIN(cbr_bytes, out_data_bytes);
+ }
+ max_len_sum = nb_frames + repacketize_len - max_header_bytes;
+
+ ALLOC(tmp_data, max_len_sum, unsigned char);
+ curr_data = tmp_data;
+ ALLOC(rp, 1, OpusRepacketizer);
+ opus_repacketizer_init(rp);
+
+
+ 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 first_frame;
+ int frame_to_celt;
+ int frame_redundancy;
+ opus_int32 curr_max;
+ /* Attempt DRED encoding until we have a non-DTX frame. In case of DTX refresh,
+ that allows for DRED not to be in the first frame. */
+ first_frame = (i == 0) || (i == dtx_count);
+ 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 */
+ frame_to_celt = to_celt && i==nb_frames-1;
+ frame_redundancy = redundancy && (frame_to_celt || (!to_celt && i==0));
+
+ curr_max = IMIN(bitrate_to_bits(st->bitrate_bps, st->Fs, enc_frame_size)/8, max_len_sum/nb_frames);
+#ifdef ENABLE_DRED
+ curr_max = IMIN(curr_max, (max_len_sum-bitrate_to_bits(dred_bitrate_bps, st->Fs, frame_size)/8)/nb_frames);
+ if (first_frame) curr_max += bitrate_to_bits(dred_bitrate_bps, st->Fs, frame_size)/8;
+#endif
+#ifdef ENABLE_QEXT
+ /* Leave room for signaling the extension size once we repacketize. */
+ if (st->enable_qext)
+ curr_max -= curr_max/254;
+#endif
+ curr_max = IMIN(max_len_sum-tot_size, curr_max);
+#ifndef DISABLE_FLOAT_API
+ if (analysis_read_pos_bak != -1) {
+ /* Get analysis for current frame. */
+ tonality_get_info(&st->analysis, &analysis_info, enc_frame_size);
+ }
+#endif
+ is_silence = is_digital_silence(pcm+i*(st->channels*enc_frame_size), enc_frame_size, st->channels, lsb_depth);
+
+ tmp_len = opus_encode_frame_native(st, pcm+i*(st->channels*enc_frame_size), enc_frame_size, curr_data, curr_max, float_api, first_frame,
+#ifdef ENABLE_DRED
+ dred_bitrate_bps,
+#endif
+#ifndef DISABLE_FLOAT_API
+ &analysis_info,
+#endif
+ is_silence, frame_redundancy, celt_to_silk, prefill,
+ equiv_rate, frame_to_celt
+ );
+ if (tmp_len<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ } else if (tmp_len==1) {
+ dtx_count++;
+ }
+ ret = opus_repacketizer_cat(rp, curr_data, tmp_len);
+
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ tot_size += tmp_len;
+ curr_data += tmp_len;
+ }
+ ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr && (dtx_count != nb_frames), NULL, 0);
+ if (ret<0)
+ {
+ ret = OPUS_INTERNAL_ERROR;
+ }
+ st->silk_mode.toMono = bak_to_mono;
+ RESTORE_STACK;
+ return ret;
+ } else {
+ ret = opus_encode_frame_native(st, pcm, frame_size, data, max_data_bytes, float_api, 1,
+#ifdef ENABLE_DRED
+ dred_bitrate_bps,
+#endif
+#ifndef DISABLE_FLOAT_API
+ &analysis_info,
+#endif
+ is_silence, redundancy, celt_to_silk, prefill,
+ equiv_rate, to_celt
+ );
+ RESTORE_STACK;
+ return ret;
+ }
+}
+
+static opus_int32 opus_encode_frame_native(OpusEncoder *st, const opus_res *pcm, int frame_size,
+ unsigned char *data, opus_int32 orig_max_data_bytes,
+ int float_api, int first_frame,
+#ifdef ENABLE_DRED
+ opus_int32 dred_bitrate_bps,
+#endif
+#ifndef DISABLE_FLOAT_API
+ AnalysisInfo *analysis_info,
+#endif
+ int is_silence, int redundancy, int celt_to_silk, int prefill,
+ opus_int32 equiv_rate, int to_celt)
+{
+ void *silk_enc=NULL;
+ CELTEncoder *celt_enc=NULL;
+ const CELTMode *celt_mode=NULL;
+ int i;
+ int ret=0;
+ int max_data_bytes;
+ opus_int32 nBytes;
+ ec_enc enc;
+ int bits_target;
+ int start_band = 0;
+ int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */
+ int nb_compr_bytes;
+ opus_uint32 redundant_rng = 0;
+ int cutoff_Hz;
+ int hp_freq_smth1;
+ opus_val16 HB_gain;
+ int apply_padding;
+ int frame_rate;
+ int curr_bandwidth;
+ int delay_compensation;
+ int total_buffer;
+ opus_int activity = VAD_NO_DECISION;
+ VARDECL(opus_res, pcm_buf);
+ VARDECL(opus_res, tmp_prefill);
+ SAVE_STACK;
+
+ max_data_bytes = IMIN(orig_max_data_bytes, 1276);
+ st->rangeFinal = 0;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_CELT)
+ silk_enc = (char*)st+st->silk_enc_offset;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+ celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
+ }
+ curr_bandwidth = st->bandwidth;
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY || st->application == OPUS_APPLICATION_RESTRICTED_CELT || st->application == OPUS_APPLICATION_RESTRICTED_SILK)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ total_buffer = delay_compensation;
+
+ frame_rate = st->Fs/frame_size;
+
+ if (is_silence)
+ {
+ activity = !is_silence;
+ }
+#ifndef DISABLE_FLOAT_API
+ else if (analysis_info->valid) {
+ activity = analysis_info->activity_probability >= DTX_ACTIVITY_THRESHOLD;
+ if (!activity)
+ {
+ /* Mark as active if this noise frame is sufficiently loud */
+ opus_val32 noise_energy = compute_frame_energy(pcm, frame_size, st->channels, st->arch);
+ activity = st->peak_signal_energy < (PSEUDO_SNR_THRESHOLD * noise_energy);
+ }
+ }
+#endif
+ else if (st->mode == MODE_CELT_ONLY) {
+ opus_val32 noise_energy = compute_frame_energy(pcm, frame_size, st->channels, st->arch);
+ /* Boosting peak energy a bit because we didn't just average the active frames. */
+ activity = st->peak_signal_energy < (QCONST16(PSEUDO_SNR_THRESHOLD, 0) * (opus_val64)HALF32(noise_energy));
+ }
+
+ /* 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 resetting the sampling rate control. */
+ prefill=2;
+ }
+
+ /* If we decided to go with CELT, make sure redundancy is off, no matter what
+ we decided earlier. */
+ if (st->mode == MODE_CELT_ONLY)
+ redundancy = 0;
+
+ if (redundancy)
+ {
+ redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels);
+ if (redundancy_bytes == 0)
+ redundancy = 0;
+ }
+ if (st->application == OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ redundancy = 0;
+ redundancy_bytes = 0;
+ }
+
+ /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */
+ bits_target = IMIN(8*(max_data_bytes-redundancy_bytes), bitrate_to_bits(st->bitrate_bps, st->Fs, frame_size)) - 8;
+
+ data += 1;
+
+ ec_enc_init(&enc, data, orig_max_data_bytes-1);
+
+ ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_res);
+ OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels);
+
+ if (st->mode == MODE_CELT_ONLY)
+ hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ else
+ hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15;
+
+ st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15,
+ hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) );
+
+ /* convert from log scale to Hertz */
+ cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) );
+
+ if (st->application == OPUS_APPLICATION_VOIP)
+ {
+ hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs, st->arch);
+
+#ifdef ENABLE_OSCE_TRAINING_DATA
+ /* write out high pass filtered clean signal*/
+ static FILE *fout =NULL;
+ if (fout == NULL)
+ {
+ fout = fopen("clean_hp.s16", "wb");
+ }
+
+ {
+ int idx;
+ opus_int16 tmp;
+ for (idx = 0; idx < frame_size; idx++)
+ {
+ tmp = (opus_int16) (32768 * pcm_buf[total_buffer + idx] + 0.5f);
+ fwrite(&tmp, sizeof(tmp), 1, fout);
+ }
+ }
+#endif
+ } else {
+#ifdef ENABLE_QEXT
+ /* FIXME: Avoid glitching when we switch qext on/off dynamically. */
+ if (st->enable_qext) OPUS_COPY(&pcm_buf[total_buffer*st->channels], pcm, frame_size*st->channels);
+ else
+#endif
+ dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+ }
+#ifndef FIXED_POINT
+ if (float_api)
+ {
+ opus_val32 sum;
+ sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch);
+ /* This should filter out both NaNs and ridiculous signals that could
+ cause NaNs further down. */
+ if (!(sum < 1e9f) || celt_isnan(sum))
+ {
+ OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels);
+ st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0;
+ }
+ }
+#else
+ (void)float_api;
+#endif
+
+#ifdef ENABLE_DRED
+ /* Compute the DRED features. Needs to be before SILK because of DTX. */
+ if ( st->dred_duration > 0 && st->dred_encoder.loaded ) {
+ int frame_size_400Hz;
+ /* DRED Encoder */
+ dred_compute_latents( &st->dred_encoder, &pcm_buf[total_buffer*st->channels], frame_size, total_buffer, st->arch );
+ frame_size_400Hz = frame_size*400/st->Fs;
+ OPUS_MOVE(&st->activity_mem[frame_size_400Hz], st->activity_mem, 4*DRED_MAX_FRAMES-frame_size_400Hz);
+ for (i=0;i<frame_size_400Hz;i++)
+ st->activity_mem[i] = activity;
+ } else {
+ st->dred_encoder.latents_buffer_fill = 0;
+ OPUS_CLEAR(st->activity_mem, 4*DRED_MAX_FRAMES);
+ }
+#endif
+
+ /* SILK processing */
+ HB_gain = Q15ONE;
+ if (st->mode != MODE_CELT_ONLY)
+ {
+ opus_int32 total_bitRate, celt_rate;
+ const opus_res *pcm_silk;
+
+ /* Distribute bits between SILK and CELT */
+ total_bitRate = bits_to_bitrate(bits_target, st->Fs, frame_size);
+ if( st->mode == MODE_HYBRID ) {
+ /* Base rate for SILK */
+ st->silk_mode.bitRate = compute_silk_rate_for_hybrid(total_bitRate,
+ curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded,
+ st->stream_channels);
+ if (!st->energy_masking)
+ {
+ /* Increasingly attenuate high band when it gets allocated fewer bits */
+ celt_rate = total_bitRate - st->silk_mode.bitRate;
+ HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1);
+ }
+ } else {
+ /* SILK gets all bits */
+ st->silk_mode.bitRate = total_bitRate;
+ }
+
+ /* Surround masking for SILK */
+ if (st->energy_masking && st->use_vbr && !st->lfe)
+ {
+ opus_val32 mask_sum=0;
+ celt_glog masking_depth;
+ opus_int32 rate_offset;
+ int c;
+ int end = 17;
+ opus_int16 srate = 16000;
+ if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND)
+ {
+ end = 13;
+ srate = 8000;
+ } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ {
+ end = 15;
+ srate = 12000;
+ }
+ for (c=0;c<st->channels;c++)
+ {
+ for(i=0;i<end;i++)
+ {
+ celt_glog mask;
+ mask = MAXG(MING(st->energy_masking[21*c+i],
+ GCONST(.5f)), -GCONST(2.0f));
+ if (mask > 0)
+ mask = HALF32(mask);
+ mask_sum += mask;
+ }
+ }
+ /* Conservative rate reduction, we cut the masking in half */
+ masking_depth = mask_sum / end*st->channels;
+ masking_depth += GCONST(.2f);
+ rate_offset = (opus_int32)PSHR32(MULT16_16(srate, SHR32(masking_depth, DB_SHIFT-10)), 10);
+ rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3);
+ /* Split the rate change between the SILK and CELT part for hybrid. */
+ if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND)
+ st->silk_mode.bitRate += 3*rate_offset/5;
+ else
+ st->silk_mode.bitRate += rate_offset;
+ }
+
+ st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs;
+ st->silk_mode.nChannelsAPI = st->channels;
+ st->silk_mode.nChannelsInternal = st->stream_channels;
+ if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.desiredInternalSampleRate = 8000;
+ } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.desiredInternalSampleRate = 12000;
+ } else {
+ celt_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND );
+ st->silk_mode.desiredInternalSampleRate = 16000;
+ }
+ if( st->mode == MODE_HYBRID ) {
+ /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */
+ st->silk_mode.minInternalSampleRate = 16000;
+ } else {
+ st->silk_mode.minInternalSampleRate = 8000;
+ }
+
+ st->silk_mode.maxInternalSampleRate = 16000;
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ opus_int32 effective_max_rate = bits_to_bitrate(max_data_bytes*8, st->Fs, frame_size);
+ if (frame_rate > 50)
+ effective_max_rate = effective_max_rate*2/3;
+ if (effective_max_rate < 8000)
+ {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate);
+ }
+ if (effective_max_rate < 7000)
+ {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate);
+ }
+#ifdef ENABLE_QEXT
+ /* At 96 kHz, we don't have the input resampler to do 8 or 12 kHz. */
+ if (st->Fs==96000) st->silk_mode.maxInternalSampleRate = st->silk_mode.desiredInternalSampleRate = 16000;
+#endif
+ }
+
+ st->silk_mode.useCBR = !st->use_vbr;
+
+ /* Call SILK encoder for the low band */
+
+ /* Max bits for SILK, counting ToC, redundancy bytes, and optionally redundancy. */
+ st->silk_mode.maxBits = (max_data_bytes-1)*8;
+ if (redundancy && redundancy_bytes >= 2)
+ {
+ /* Counting 1 bit for redundancy position and 20 bits for flag+size (only for hybrid). */
+ st->silk_mode.maxBits -= redundancy_bytes*8 + 1;
+ if (st->mode == MODE_HYBRID)
+ st->silk_mode.maxBits -= 20;
+ }
+ if (st->silk_mode.useCBR)
+ {
+ /* When we're in CBR mode, but we have non-SILK data to encode, switch SILK to VBR with cap to
+ save on complexity. Any variations will be absorbed by CELT and/or DRED and we can still
+ produce a constant bitrate without wasting bits. */
+#ifdef ENABLE_DRED
+ if (st->mode == MODE_HYBRID || dred_bitrate_bps > 0)
+#else
+ if (st->mode == MODE_HYBRID)
+#endif
+ {
+ /* Allow SILK to steal up to 25% of the remaining bits */
+ opus_int16 other_bits = IMAX(0, st->silk_mode.maxBits - st->silk_mode.bitRate * frame_size / st->Fs);
+ st->silk_mode.maxBits = IMAX(0, st->silk_mode.maxBits - other_bits*3/4);
+ st->silk_mode.useCBR = 0;
+ }
+ } 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 = bitrate_to_bits(maxBitRate, st->Fs, frame_size);
+ }
+ }
+
+ if (prefill && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ opus_int32 zero=0;
+ int prefill_offset;
+ /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode
+ a discontinuity. The exact location is what we need to avoid leaving any "gap"
+ in the audio when mixing with the redundant CELT frame. Here we can afford to
+ overwrite st->delay_buffer because the only thing that uses it before it gets
+ rewritten is tmp_prefill[] and even then only the part after the ramp really
+ gets used (rather than sent to the encoder and discarded) */
+ prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400);
+ gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset,
+ 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs);
+ OPUS_CLEAR(st->delay_buffer, prefill_offset);
+ pcm_silk = st->delay_buffer;
+ 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;
+ }
+
+ pcm_silk = pcm_buf+total_buffer*st->channels;
+ ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity );
+ if( ret ) {
+ /*fprintf (stderr, "SILK encode error: %d\n", ret);*/
+ /* Handle error */
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+
+ /* Extract SILK internal bandwidth for signaling in first byte */
+ if( st->mode == MODE_SILK_ONLY ) {
+ if( st->silk_mode.internalSampleRate == 8000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ } else if( st->silk_mode.internalSampleRate == 12000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if( st->silk_mode.internalSampleRate == 16000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ }
+ } else {
+ celt_assert( st->silk_mode.internalSampleRate == 16000 );
+ }
+
+ st->silk_mode.opusCanSwitch = st->silk_mode.switchReady && !st->nonfinal_frame;
+
+ if (activity == VAD_NO_DECISION) {
+ activity = (st->silk_mode.signalType != TYPE_NO_VOICE_ACTIVITY);
+#ifdef ENABLE_DRED
+ for (i=0;i<frame_size*400/st->Fs;i++)
+ st->activity_mem[i] = activity;
+#endif
+ }
+ if (nBytes==0)
+ {
+ st->rangeFinal = 0;
+ data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+ RESTORE_STACK;
+ return 1;
+ }
+
+ /* FIXME: How do we allocate the redundancy for CBR? */
+ if (st->silk_mode.opusCanSwitch)
+ {
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels);
+ redundancy = (redundancy_bytes != 0);
+ }
+ celt_to_silk = 0;
+ st->silk_bw_switch = 1;
+ }
+ }
+
+ /* CELT processing */
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ int endband=21;
+
+ switch(curr_bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband));
+ celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+ }
+ if (st->mode != MODE_SILK_ONLY)
+ {
+ opus_val32 celt_pred=2;
+ /* We may still decide to disable prediction later */
+ if (st->silk_mode.reducedDependency)
+ celt_pred = 0;
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred));
+ }
+
+ ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_res);
+ if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0
+ && st->application != OPUS_APPLICATION_RESTRICTED_CELT)
+ {
+ OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400);
+ }
+
+ if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0)
+ {
+ OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer));
+ OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)],
+ &pcm_buf[0],
+ (frame_size+total_buffer)*st->channels);
+ } else {
+ OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels);
+ }
+ /* gain_fade() and stereo_fade() need to be after the buffer copying
+ because we don't want any of this to affect the SILK part */
+ if( ( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) && celt_mode != NULL ) {
+ gain_fade(pcm_buf, pcm_buf,
+ st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs);
+ }
+ st->prev_HB_gain = HB_gain;
+ if (st->mode != MODE_HYBRID || st->stream_channels==1)
+ {
+ if (equiv_rate > 32000)
+ st->silk_mode.stereoWidth_Q14 = 16384;
+ else if (equiv_rate < 16000)
+ st->silk_mode.stereoWidth_Q14 = 0;
+ else
+ st->silk_mode.stereoWidth_Q14 = 16384 - 2048*(opus_int32)(32000-equiv_rate)/(equiv_rate-14000);
+ }
+ if( !st->energy_masking && st->channels == 2 ) {
+ /* Apply stereo width reduction (at low bitrates) */
+ if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) {
+ opus_val16 g1, g2;
+ g1 = st->hybrid_stereo_width_Q14;
+ g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14);
+#ifdef FIXED_POINT
+ g1 = g1==16384 ? Q15ONE : SHL16(g1,1);
+ g2 = g2==16384 ? Q15ONE : SHL16(g2,1);
+#else
+ g1 *= (1.f/16384);
+ g2 *= (1.f/16384);
+#endif
+ if ( celt_mode != NULL )
+ {
+ stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap,
+ frame_size, st->channels, celt_mode->window, st->Fs);
+ }
+ st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14;
+ }
+ }
+
+ if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1))
+ {
+ /* For SILK mode, the redundancy is inferred from the length */
+ if (st->mode == MODE_HYBRID)
+ ec_enc_bit_logp(&enc, redundancy, 12);
+ if (redundancy)
+ {
+ int max_redundancy;
+ ec_enc_bit_logp(&enc, celt_to_silk, 1);
+ if (st->mode == MODE_HYBRID)
+ {
+ /* Reserve the 8 bits needed for the redundancy length,
+ and at least a few bits for CELT if possible */
+ max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+8+3+7)>>3);
+ }
+ else
+ max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3);
+ /* Target the same bit-rate for redundancy as for the rest,
+ up to a max of 257 bytes */
+ redundancy_bytes = IMIN(max_redundancy, redundancy_bytes);
+ redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes));
+ if (st->mode == MODE_HYBRID)
+ ec_enc_uint(&enc, redundancy_bytes-2, 256);
+ }
+ } else {
+ redundancy = 0;
+ }
+
+ if (!redundancy)
+ {
+ st->silk_bw_switch = 0;
+ redundancy_bytes = 0;
+ }
+ if (st->mode != MODE_CELT_ONLY)start_band=17;
+
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ ret = (ec_tell(&enc)+7)>>3;
+ ec_enc_done(&enc);
+ nb_compr_bytes = ret;
+ } else {
+ nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes;
+#ifdef ENABLE_QEXT
+ if (st->mode == MODE_CELT_ONLY && st->enable_qext) {
+ celt_assert(redundancy_bytes==0);
+ nb_compr_bytes = orig_max_data_bytes-1;
+ }
+#endif
+#ifdef ENABLE_DRED
+ if (st->dred_duration > 0)
+ {
+ int max_celt_bytes;
+ opus_int32 dred_bytes = bitrate_to_bits(dred_bitrate_bps, st->Fs, frame_size)/8;
+ /* Allow CELT to steal up to 25% of the remaining bits. */
+ max_celt_bytes = nb_compr_bytes - dred_bytes*3/4;
+ /* But try to give CELT at least 5 bytes to prevent a mismatch with
+ the redundancy signaling. */
+ max_celt_bytes = IMAX((ec_tell(&enc)+7)/8 + 5, max_celt_bytes);
+ /* Subject to the original max. */
+ nb_compr_bytes = IMIN(nb_compr_bytes, max_celt_bytes);
+ }
+#endif
+ ec_enc_shrink(&enc, nb_compr_bytes);
+ }
+
+#ifndef DISABLE_FLOAT_API
+ if (redundancy || st->mode != MODE_SILK_ONLY)
+ celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(analysis_info));
+#endif
+ if (st->mode == MODE_HYBRID) {
+ SILKInfo info;
+ info.signalType = st->silk_mode.signalType;
+ info.offset = st->silk_mode.offset;
+ celt_encoder_ctl(celt_enc, CELT_SET_SILK_INFO(&info));
+ }
+
+ /* 5 ms redundant frame for CELT->SILK */
+ if (redundancy && celt_to_silk)
+ {
+ int err;
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+ err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL);
+ if (err < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ }
+
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band));
+
+ data[-1] = 0;
+ if (st->mode != MODE_SILK_ONLY)
+ {
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr));
+ if (st->mode == MODE_HYBRID)
+ {
+ if( st->use_vbr ) {
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0));
+ }
+ } else {
+ if (st->use_vbr)
+ {
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps));
+ }
+ }
+#ifdef ENABLE_DRED
+ /* When Using DRED CBR, we can actually make the CELT part VBR and have DRED pick up the slack. */
+ if (!st->use_vbr && st->dred_duration > 0)
+ {
+ opus_int32 celt_bitrate = st->bitrate_bps;
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0));
+ if (st->mode == MODE_HYBRID) {
+ celt_bitrate -= st->silk_mode.bitRate;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(celt_bitrate));
+ }
+#endif
+ if (st->mode != st->prev_mode && st->prev_mode > 0 && st->application != OPUS_APPLICATION_RESTRICTED_CELT)
+ {
+ unsigned char dummy[2];
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+
+ /* Prefilling */
+ celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL);
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+ }
+ /* If false, we already busted the budget and we'll end up with a "PLC frame" */
+ if (ec_tell(&enc) <= 8*nb_compr_bytes)
+ {
+#ifdef ENABLE_QEXT
+ if (st->mode == MODE_CELT_ONLY) celt_encoder_ctl(celt_enc, OPUS_SET_QEXT(st->enable_qext));
+#endif
+ ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc);
+#ifdef ENABLE_QEXT
+ celt_encoder_ctl(celt_enc, OPUS_SET_QEXT(0));
+#endif
+ 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 && nb_compr_bytes != ret)
+ {
+ OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes);
+ nb_compr_bytes = ret+redundancy_bytes;
+ }
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&st->rangeFinal));
+ } else {
+ st->rangeFinal = enc.rng;
+ }
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy && !celt_to_silk)
+ {
+ int err;
+ unsigned char dummy[2];
+ int N2, N4;
+ N2 = st->Fs/200;
+ N4 = st->Fs/400;
+
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+
+ if (st->mode == MODE_HYBRID)
+ {
+ /* Shrink packet to what the encoder actually used. */
+ nb_compr_bytes = ret;
+ ec_enc_shrink(&enc, nb_compr_bytes);
+ }
+ /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */
+ celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL);
+
+ err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL);
+ if (err < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ }
+
+
+
+ /* Signalling the mode in the first byte */
+ data--;
+ data[0] |= gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+
+ st->rangeFinal ^= redundant_rng;
+
+ if (to_celt)
+ st->prev_mode = MODE_CELT_ONLY;
+ else
+ st->prev_mode = st->mode;
+ st->prev_channels = st->stream_channels;
+ st->prev_framesize = frame_size;
+
+ st->first = 0;
+
+ /* DTX decision */
+ if (st->use_dtx && !st->silk_mode.useDTX)
+ {
+ if (decide_dtx_mode(activity, &st->nb_no_activity_ms_Q1, 2*1000*frame_size/st->Fs))
+ {
+ 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_ms_Q1 = 0;
+ }
+
+ /* In the unlikely case that the SILK encoder busted its target, tell
+ the decoder to call the PLC */
+ if (ec_tell(&enc) > (max_data_bytes-1)*8)
+ {
+ if (max_data_bytes < 2)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ data[1] = 0;
+ ret = 1;
+ st->rangeFinal = 0;
+ } else if (st->mode==MODE_SILK_ONLY&&!redundancy)
+ {
+ /*When in LPC only mode it's perfectly
+ reasonable to strip off trailing zero bytes as
+ the required range decoder behavior is to
+ fill these in. This can't be done when the MDCT
+ modes are used because the decoder needs to know
+ the actual length for allocation purposes.*/
+ while(ret>2&&data[ret]==0)ret--;
+ }
+ /* Count ToC and redundancy */
+ ret += 1+redundancy_bytes;
+ apply_padding = !st->use_vbr;
+#ifdef ENABLE_DRED
+ if (st->dred_duration > 0 && st->dred_encoder.loaded && first_frame) {
+ opus_extension_data extension;
+ unsigned char buf[DRED_MAX_DATA_SIZE];
+ int dred_chunks;
+ int dred_bytes_left;
+ dred_chunks = IMIN((st->dred_duration+5)/4, DRED_NUM_REDUNDANCY_FRAMES/2);
+ if (st->use_vbr) dred_chunks = IMIN(dred_chunks, st->dred_target_chunks);
+ /* Remaining space for DRED, accounting for cost the 3 extra bytes for code 3, padding length, and extension number. */
+ dred_bytes_left = IMIN(DRED_MAX_DATA_SIZE, orig_max_data_bytes-ret-3);
+ /* Account for the extra bytes required to signal large padding length. */
+ dred_bytes_left -= (dred_bytes_left+1+DRED_EXPERIMENTAL_BYTES)/255;
+ /* Check whether we actually have something to encode. */
+ if (dred_chunks >= 1 && dred_bytes_left >= DRED_MIN_BYTES+DRED_EXPERIMENTAL_BYTES) {
+ int dred_bytes;
+#ifdef DRED_EXPERIMENTAL_VERSION
+ /* Add temporary extension type and version.
+ These bytes will be removed once extension is finalized. */
+ buf[0] = 'D';
+ buf[1] = DRED_EXPERIMENTAL_VERSION;
+#endif
+ dred_bytes = dred_encode_silk_frame(&st->dred_encoder, buf+DRED_EXPERIMENTAL_BYTES, dred_chunks, dred_bytes_left-DRED_EXPERIMENTAL_BYTES,
+ st->dred_q0, st->dred_dQ, st->dred_qmax, st->activity_mem, st->arch);
+ if (dred_bytes > 0) {
+ dred_bytes += DRED_EXPERIMENTAL_BYTES;
+ celt_assert(dred_bytes <= dred_bytes_left);
+ extension.id = DRED_EXTENSION_ID;
+ extension.frame = 0;
+ extension.data = buf;
+ extension.len = dred_bytes;
+ ret = opus_packet_pad_impl(data, ret, orig_max_data_bytes, !st->use_vbr, &extension, 1);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ apply_padding = 0;
+ }
+ }
+ }
+#else
+ (void)first_frame; /* Avoids a warning about first_frame being unused. */
+#endif
+ if (apply_padding)
+ {
+ if (opus_packet_pad(data, ret, orig_max_data_bytes) != OPUS_OK)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ ret = orig_max_data_bytes;
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+
+
+#if defined(FIXED_POINT) && !defined(ENABLE_RES24)
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int frame_size;
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, st->Fs);
+ return opus_encode_native(st, pcm, frame_size, data, max_data_bytes, 16,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0);
+}
+#else
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ VARDECL(opus_res, in);
+ ALLOC_STACK;
+
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, st->Fs);
+ if (frame_size <= 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ ALLOC(in, frame_size*st->channels, opus_res);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = INT16TORES(pcm[i]);
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 1);
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+#if defined(FIXED_POINT) && defined(ENABLE_RES24)
+opus_int32 opus_encode24(OpusEncoder *st, const opus_int32 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int frame_size;
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, st->Fs);
+ return opus_encode_native(st, pcm, frame_size, data, max_data_bytes, MAX_ENCODING_DEPTH,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_int24, 0);
+}
+#else
+opus_int32 opus_encode24(OpusEncoder *st, const opus_int32 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ VARDECL(opus_res, in);
+ ALLOC_STACK;
+
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, st->Fs);
+ if (frame_size <= 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ ALLOC(in, frame_size*st->channels, opus_res);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = INT24TORES(pcm[i]);
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, MAX_ENCODING_DEPTH,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_int24, 1);
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+
+#ifndef DISABLE_FLOAT_API
+
+# if !defined(FIXED_POINT)
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 out_data_bytes)
+{
+ int frame_size;
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, st->Fs);
+ return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, MAX_ENCODING_DEPTH,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1);
+}
+# else
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ VARDECL(opus_res, in);
+ ALLOC_STACK;
+
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, st->Fs);
+ if (frame_size <= 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ ALLOC(in, frame_size*st->channels, opus_res);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = FLOAT2RES(pcm[i]);
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, MAX_ENCODING_DEPTH,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1);
+ RESTORE_STACK;
+ return ret;
+}
+# endif
+
+#endif
+
+
+int opus_encoder_ctl(OpusEncoder *st, int request, ...)
+{
+ int ret;
+ CELTEncoder *celt_enc=NULL;
+ va_list ap;
+
+ ret = OPUS_OK;
+ va_start(ap, request);
+
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+ switch (request)
+ {
+ case OPUS_SET_APPLICATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (st->application == OPUS_APPLICATION_RESTRICTED_SILK || st->application == OPUS_APPLICATION_RESTRICTED_CELT)
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO
+ && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ || (!st->first && st->application != value))
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ st->application = value;
+#ifndef DISABLE_FLOAT_API
+ st->analysis.application = value;
+#endif
+ }
+ break;
+ case OPUS_GET_APPLICATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->application;
+ }
+ break;
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
+ {
+ if (value <= 0)
+ goto bad_arg;
+ else if (value <= 500)
+ value = 500;
+ else if (value > (opus_int32)750000*st->channels)
+ value = (opus_int32)750000*st->channels;
+ }
+ st->user_bitrate_bps = value;
+ }
+ break;
+ case OPUS_GET_BITRATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276);
+ }
+ break;
+ case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if((value<1 || value>st->channels) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->force_channels = value;
+ }
+ break;
+ case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->force_channels;
+ }
+ break;
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND)
+ {
+ goto bad_arg;
+ }
+ st->max_bandwidth = value;
+ if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+ break;
+ case OPUS_GET_MAX_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->max_bandwidth;
+ }
+ break;
+ case OPUS_SET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->user_bandwidth = value;
+ if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+ break;
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->bandwidth;
+ }
+ break;
+ case OPUS_SET_DTX_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->use_dtx = value;
+ }
+ break;
+ case OPUS_GET_DTX_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->use_dtx;
+ }
+ break;
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>10)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.complexity = value;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value));
+ }
+ break;
+ case OPUS_GET_COMPLEXITY_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.complexity;
+ }
+ break;
+ case OPUS_SET_INBAND_FEC_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>2)
+ {
+ goto bad_arg;
+ }
+ st->fec_config = value;
+ st->silk_mode.useInBandFEC = (value != 0);
+ }
+ break;
+ case OPUS_GET_INBAND_FEC_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->fec_config;
+ }
+ break;
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value < 0 || value > 100)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.packetLossPercentage = value;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value));
+ }
+ break;
+ case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.packetLossPercentage;
+ }
+ break;
+ case OPUS_SET_VBR_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->use_vbr = value;
+ st->silk_mode.useCBR = 1-value;
+ }
+ break;
+ case OPUS_GET_VBR_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->use_vbr;
+ }
+ break;
+ case OPUS_SET_VOICE_RATIO_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<-1 || value>100)
+ {
+ goto bad_arg;
+ }
+ st->voice_ratio = value;
+ }
+ break;
+ case OPUS_GET_VOICE_RATIO_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->voice_ratio;
+ }
+ break;
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->vbr_constraint = value;
+ }
+ break;
+ case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->vbr_constraint;
+ }
+ break;
+ case OPUS_SET_SIGNAL_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC)
+ {
+ goto bad_arg;
+ }
+ st->signal_type = value;
+ }
+ break;
+ case OPUS_GET_SIGNAL_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->signal_type;
+ }
+ break;
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs/400;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY && st->application != OPUS_APPLICATION_RESTRICTED_CELT)
+ *value += st->delay_compensation;
+ }
+ break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->rangeFinal;
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<8 || value>24)
+ {
+ goto bad_arg;
+ }
+ st->lsb_depth=value;
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->lsb_depth;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS &&
+ value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS &&
+ value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS &&
+ value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_80_MS &&
+ value != OPUS_FRAMESIZE_100_MS && value != OPUS_FRAMESIZE_120_MS)
+ {
+ goto bad_arg;
+ }
+ st->variable_duration = value;
+ }
+ break;
+ case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->variable_duration;
+ }
+ break;
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value > 1 || value < 0)
+ goto bad_arg;
+ st->silk_mode.reducedDependency = value;
+ }
+ break;
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ goto bad_arg;
+ *value = st->silk_mode.reducedDependency;
+ }
+ break;
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ 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;
+ }
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value));
+ else
+ *value = 0;
+ }
+ break;
+#ifdef ENABLE_DRED
+ case OPUS_SET_DRED_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>DRED_MAX_FRAMES)
+ {
+ goto bad_arg;
+ }
+ st->dred_duration = value;
+ st->silk_mode.useDRED = !!value;
+ }
+ break;
+ case OPUS_GET_DRED_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->dred_duration;
+ }
+ break;
+#endif
+#ifdef ENABLE_QEXT
+ case OPUS_SET_QEXT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->enable_qext = value;
+ }
+ break;
+ case OPUS_GET_QEXT_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->enable_qext;
+ }
+ break;
+#endif
+ case OPUS_RESET_STATE:
+ {
+ void *silk_enc;
+ silk_EncControlStruct dummy;
+ char *start;
+ silk_enc = (char*)st+st->silk_enc_offset;
+#ifndef DISABLE_FLOAT_API
+ tonality_analysis_reset(&st->analysis);
+#endif
+
+ start = (char*)&st->OPUS_ENCODER_RESET_START;
+ OPUS_CLEAR(start, st->silk_enc_offset - (start - (char*)st));
+
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ if (st->application != OPUS_APPLICATION_RESTRICTED_CELT)
+ silk_InitEncoder( silk_enc, st->channels, st->arch, &dummy );
+#ifdef ENABLE_DRED
+ /* Initialize DRED Encoder */
+ dred_encoder_reset( &st->dred_encoder );
+#endif
+ st->stream_channels = st->channels;
+ st->hybrid_stereo_width_Q14 = 1 << 14;
+ st->prev_HB_gain = Q15ONE;
+ st->first = 1;
+ st->mode = MODE_HYBRID;
+ st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ }
+ break;
+ case OPUS_SET_FORCE_MODE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->user_forced_mode = value;
+ }
+ break;
+ case OPUS_SET_LFE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->lfe = value;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value));
+ }
+ break;
+ case OPUS_SET_ENERGY_MASK_REQUEST:
+ {
+ celt_glog *value = va_arg(ap, celt_glog*);
+ st->energy_masking = value;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ 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. */
+ silk_encoder *silk_enc = (silk_encoder*)(void *)((char*)st+st->silk_enc_offset);
+ *value = silk_enc->state_Fxx[0].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX;
+ /* Stereo: check second channel unless only the middle channel was encoded. */
+ if(*value == 1 && st->silk_mode.nChannelsInternal == 2 && silk_enc->prev_decode_only_middle == 0) {
+ *value = silk_enc->state_Fxx[1].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX;
+ }
+ }
+ else if (st->use_dtx) {
+ /* DTX determined by Opus. */
+ *value = st->nb_no_activity_ms_Q1 >= NB_SPEECH_FRAMES_BEFORE_DTX*20*2;
+ }
+ else {
+ *value = 0;
+ }
+ }
+ break;
+#ifdef USE_WEIGHTS_FILE
+ case OPUS_SET_DNN_BLOB_REQUEST:
+ {
+ const unsigned char *data = va_arg(ap, const unsigned char *);
+ opus_int32 len = va_arg(ap, opus_int32);
+ if(len<0 || data == NULL)
+ {
+ goto bad_arg;
+ }
+#ifdef ENABLE_DRED
+ ret = dred_encoder_load_model(&st->dred_encoder, data, len);
+#endif
+ }
+ break;
+#endif
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ celt_assert(celt_enc != NULL);
+ ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value));
+ }
+ break;
+ default:
+ /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_encoder_destroy(OpusEncoder *st)
+{
+ opus_free(st);
+}
--- /dev/null
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opus_multistream.h"
+#include "opus.h"
+#include "opus_private.h"
+#include "stack_alloc.h"
+#include <stdarg.h>
+#include "float_cast.h"
+#include "os_support.h"
+#include "mathops.h"
+#include "mdct.h"
+#include "modes.h"
+#include "bands.h"
+#include "quant_bands.h"
+#include "pitch.h"
+
+typedef struct {
+ int nb_streams;
+ int nb_coupled_streams;
+ unsigned char mapping[8];
+} VorbisLayout;
+
+/* Index is nb_channel-1*/
+static const VorbisLayout vorbis_mappings[8] = {
+ {1, 0, {0}}, /* 1: mono */
+ {1, 1, {0, 1}}, /* 2: stereo */
+ {2, 1, {0, 2, 1}}, /* 3: 1-d surround */
+ {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */
+ {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */
+ {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */
+ {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */
+ {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
+};
+
+#ifdef ENABLE_QEXT
+#define MAX_OVERLAP 240
+#else
+#define MAX_OVERLAP 120
+#endif
+
+static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_init(NULL, st->Fs, 2, st->application);
+ mono_size = opus_encoder_init(NULL, st->Fs, 1, st->application);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ /* void* cast avoids clang -Wcast-align warning */
+ return (opus_val32*)(void*)(ptr+st->layout.nb_channels*MAX_OVERLAP*sizeof(opus_val32));
+}
+
+static opus_val32 *ms_get_window_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_init(NULL, st->Fs, 2, st->application);
+ mono_size = opus_encoder_init(NULL, st->Fs, 1, st->application);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ /* void* cast avoids clang -Wcast-align warning */
+ return (opus_val32*)(void*)ptr;
+}
+
+static int validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams)
+{
+ int order_plus_one;
+ int acn_channels;
+ int nondiegetic_channels;
+
+ if (nb_channels < 1 || nb_channels > 227)
+ return 0;
+
+ order_plus_one = isqrt32(nb_channels);
+ acn_channels = order_plus_one * order_plus_one;
+ nondiegetic_channels = nb_channels - acn_channels;
+
+ if (nondiegetic_channels != 0 && nondiegetic_channels != 2)
+ return 0;
+
+ if (nb_streams)
+ *nb_streams = acn_channels + (nondiegetic_channels != 0);
+ if (nb_coupled_streams)
+ *nb_coupled_streams = nondiegetic_channels != 0;
+ return 1;
+}
+
+static int validate_encoder_layout(const ChannelLayout *layout)
+{
+ int s;
+ for (s=0;s<layout->nb_streams;s++)
+ {
+ if (s < layout->nb_coupled_streams)
+ {
+ if (get_left_channel(layout, s, -1)==-1)
+ return 0;
+ if (get_right_channel(layout, s, -1)==-1)
+ return 0;
+ } else {
+ if (get_mono_channel(layout, s, -1)==-1)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void channel_pos(int channels, int pos[8])
+{
+ /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
+ if (channels==4)
+ {
+ pos[0]=1;
+ pos[1]=3;
+ pos[2]=1;
+ pos[3]=3;
+ } else if (channels==3||channels==5||channels==6)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=0;
+ } else if (channels==7)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=2;
+ pos[6]=0;
+ } else if (channels==8)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=1;
+ pos[6]=3;
+ pos[7]=0;
+ }
+}
+
+#if 1
+/* Computes a rough approximation of log2(2^a + 2^b) */
+static opus_val16 logSum(celt_glog a, celt_glog b)
+{
+ celt_glog max;
+ celt_glog diff;
+ celt_glog frac;
+ static const celt_glog diff_table[17] = {
+ GCONST(0.5000000f), GCONST(0.2924813f), GCONST(0.1609640f), GCONST(0.0849625f),
+ GCONST(0.0437314f), GCONST(0.0221971f), GCONST(0.0111839f), GCONST(0.0056136f),
+ GCONST(0.0028123f)
+ };
+ int low;
+ if (a>b)
+ {
+ max = a;
+ diff = SUB32(a,b);
+ } else {
+ max = b;
+ diff = SUB32(b,a);
+ }
+ if (!(diff < GCONST(8.f))) /* inverted to catch NaNs */
+ return max;
+#ifdef FIXED_POINT
+ low = SHR32(diff, DB_SHIFT-1);
+ frac = VSHR32(diff - SHL32(low, DB_SHIFT-1), DB_SHIFT-16);
+#else
+ low = (int)floor(2*diff);
+ frac = 2*diff - low;
+#endif
+ return max + diff_table[low] + MULT16_32_Q15(frac, SUB32(diff_table[low+1], diff_table[low]));
+}
+#else
+opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ return log2(pow(4, a)+ pow(4, b))/2;
+}
+#endif
+
+void surround_analysis(const CELTMode *celt_mode, const void *pcm, celt_glog *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem,
+ int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch
+)
+{
+ int c;
+ int i;
+ int LM;
+ int pos[8] = {0};
+ int upsample;
+ int frame_size;
+ int freq_size;
+ opus_val16 channel_offset;
+ opus_val32 bandE[21];
+ celt_glog maskLogE[3][21];
+ VARDECL(opus_val32, in);
+ VARDECL(opus_res, x);
+ VARDECL(opus_val32, freq);
+ SAVE_STACK;
+
+ upsample = resampling_factor(rate);
+ frame_size = len*upsample;
+
+ /* LM = log2(frame_size / 120) */
+ for (LM=0;LM<celt_mode->maxLM;LM++)
+ if (celt_mode->shortMdctSize<<LM==frame_size)
+ break;
+
+ freq_size = celt_mode->shortMdctSize<<LM;
+
+ ALLOC(in, frame_size+overlap, opus_val32);
+ ALLOC(x, len, opus_res);
+ ALLOC(freq, freq_size, opus_val32);
+
+ channel_pos(channels, pos);
+
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] = -GCONST(28.f);
+
+ 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);
+ celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0);
+#ifndef FIXED_POINT
+ {
+ opus_val32 sum;
+ sum = celt_inner_prod(in, in, frame_size+overlap, 0);
+ /* This should filter out both NaNs and ridiculous signals that could
+ cause NaNs further down. */
+ if (!(sum < 1e18f) || celt_isnan(sum))
+ {
+ OPUS_CLEAR(in, frame_size+overlap);
+ preemph_mem[c] = 0;
+ }
+ }
+#endif
+ OPUS_CLEAR(bandE, 21);
+ for (frame=0;frame<nb_frames;frame++)
+ {
+ opus_val32 tmpE[21];
+ clt_mdct_forward(&celt_mode->mdct, in+freq_size*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]);
+ }
+ 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++)
+ bandLogE[21*c+i] = MAXG(bandLogE[21*c+i], bandLogE[21*c+i-1]-GCONST(1.f));
+ for (i=19;i>=0;i--)
+ bandLogE[21*c+i] = MAXG(bandLogE[21*c+i], bandLogE[21*c+i+1]-GCONST(2.f));
+ if (pos[c]==1)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]);
+ } else if (pos[c]==3)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]);
+ } else if (pos[c]==2)
+ {
+ for (i=0;i<21;i++)
+ {
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-GCONST(.5f));
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-GCONST(.5f));
+ }
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/21);
+#endif
+ OPUS_COPY(mem+c*overlap, in+frame_size, overlap);
+ }
+ for (i=0;i<21;i++)
+ maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]);
+ channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1)));
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] += channel_offset;
+#if 0
+ for (c=0;c<3;c++)
+ {
+ for (i=0;i<21;i++)
+ printf("%f ", maskLogE[c][i]);
+ }
+#endif
+ for (c=0;c<channels;c++)
+ {
+ celt_glog *mask;
+ if (pos[c]!=0)
+ {
+ mask = &maskLogE[pos[c]-1][0];
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = bandLogE[21*c+i] - mask[i];
+ } else {
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = 0;
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ printf("\n");
+#endif
+#if 0
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/(float)QCONST32(21.f, DB_SHIFT));
+ printf("\n");
+#endif
+ }
+ RESTORE_STACK;
+}
+
+opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+ int coupled_size;
+ int mono_size;
+
+ if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ return align(sizeof(OpusMSEncoder))
+ + nb_coupled_streams * align(coupled_size)
+ + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family)
+{
+ int nb_streams;
+ int nb_coupled_streams;
+ opus_int32 size;
+
+ if (mapping_family==0)
+ {
+ if (channels==1)
+ {
+ nb_streams=1;
+ nb_coupled_streams=0;
+ } else if (channels==2)
+ {
+ nb_streams=1;
+ nb_coupled_streams=1;
+ } else
+ return 0;
+ } else if (mapping_family==1 && channels<=8 && channels>=1)
+ {
+ nb_streams=vorbis_mappings[channels-1].nb_streams;
+ nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+ } else if (mapping_family==255)
+ {
+ nb_streams=channels;
+ nb_coupled_streams=0;
+ } else if (mapping_family==2)
+ {
+ if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams))
+ return 0;
+ } else
+ return 0;
+ size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
+ if (channels>2)
+ {
+ size += channels*(MAX_OVERLAP*sizeof(opus_val32) + sizeof(opus_val32));
+ }
+ return size;
+}
+
+static int opus_multistream_encoder_init_impl(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ MappingType mapping_type
+)
+{
+ int coupled_size;
+ int mono_size;
+ int i, ret;
+ char *ptr;
+
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams) ||
+ (streams+coupled_streams>channels))
+ return OPUS_BAD_ARG;
+
+ coupled_size = opus_encoder_init(NULL, Fs, 2, application);
+ if (coupled_size < 0)
+ return coupled_size;
+ mono_size = opus_encoder_init(NULL, Fs, 1, application);
+ if (mono_size < 0)
+ return mono_size;
+ if (st == NULL)
+ {
+ int surround_size=0;
+ if (mapping_type == MAPPING_TYPE_SURROUND) {
+ surround_size = channels*(MAX_OVERLAP*sizeof(opus_val32) + sizeof(opus_val32));
+ }
+
+ return align(sizeof(OpusMSEncoder)) + coupled_streams*align(coupled_size)
+ + (streams-coupled_streams)*align(mono_size) + surround_size;
+ }
+
+ st->arch = opus_select_arch();
+ st->layout.nb_channels = channels;
+ st->layout.nb_streams = streams;
+ st->layout.nb_coupled_streams = coupled_streams;
+ if (mapping_type != MAPPING_TYPE_SURROUND)
+ st->lfe_stream = -1;
+ st->bitrate_bps = OPUS_AUTO;
+ st->application = application;
+ st->Fs = Fs;
+ 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 (!validate_encoder_layout(&st->layout))
+ return OPUS_BAD_ARG;
+ if (mapping_type == MAPPING_TYPE_AMBISONICS &&
+ !validate_ambisonics(st->layout.nb_channels, NULL, NULL))
+ return OPUS_BAD_ARG;
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (i=0;i<st->layout.nb_coupled_streams;i++)
+ {
+ ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
+ if(ret!=OPUS_OK)return ret;
+ if (i==st->lfe_stream)
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+ ptr += align(coupled_size);
+ }
+ for (;i<st->layout.nb_streams;i++)
+ {
+ ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
+ if(ret!=OPUS_OK)return ret;
+ if (i==st->lfe_stream)
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+ ptr += align(mono_size);
+ }
+ if (mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), channels);
+ OPUS_CLEAR(ms_get_window_mem(st), channels*MAX_OVERLAP);
+ }
+ st->mapping_type = mapping_type;
+ return OPUS_OK;
+}
+
+int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+)
+{
+ return opus_multistream_encoder_init_impl(st, Fs, channels, streams,
+ coupled_streams, mapping,
+ application, MAPPING_TYPE_NONE);
+}
+
+int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+)
+{
+ MappingType mapping_type;
+ int lfe_stream;
+
+ if ((channels>255) || (channels<1))
+ return OPUS_BAD_ARG;
+ lfe_stream = -1;
+ if (mapping_family==0)
+ {
+ if (channels==1)
+ {
+ *streams=1;
+ *coupled_streams=0;
+ mapping[0]=0;
+ } else if (channels==2)
+ {
+ *streams=1;
+ *coupled_streams=1;
+ mapping[0]=0;
+ mapping[1]=1;
+ } else
+ return OPUS_UNIMPLEMENTED;
+ } else if (mapping_family==1 && channels<=8 && channels>=1)
+ {
+ int i;
+ *streams=vorbis_mappings[channels-1].nb_streams;
+ *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+ for (i=0;i<channels;i++)
+ mapping[i] = vorbis_mappings[channels-1].mapping[i];
+ if (channels>=6)
+ lfe_stream = *streams-1;
+ } else if (mapping_family==255)
+ {
+ int i;
+ *streams=channels;
+ *coupled_streams=0;
+ for(i=0;i<channels;i++)
+ mapping[i] = i;
+ } else if (mapping_family==2)
+ {
+ 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;
+ } else
+ return OPUS_UNIMPLEMENTED;
+
+ if (channels>2 && mapping_family==1) {
+ mapping_type = MAPPING_TYPE_SURROUND;
+ } else if (mapping_family==2)
+ {
+ mapping_type = MAPPING_TYPE_AMBISONICS;
+ } else
+ {
+ mapping_type = MAPPING_TYPE_NONE;
+ }
+ if (st != NULL) {
+ st->lfe_stream = lfe_stream;
+ }
+ return opus_multistream_encoder_init_impl(st, Fs, channels, *streams,
+ *coupled_streams, mapping,
+ application, mapping_type);
+}
+
+OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+)
+{
+ int ret;
+ OpusMSEncoder *st;
+ opus_int32 size;
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams) ||
+ (streams+coupled_streams>channels))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ size = opus_multistream_encoder_init(NULL, Fs, channels, streams, coupled_streams, mapping, application);
+ if (size < 0)
+ {
+ if (error)
+ *error = size;
+ return NULL;
+ }
+ st = (OpusMSEncoder *)opus_alloc(size);
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+
+OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+)
+{
+ int ret;
+ opus_int32 size;
+ OpusMSEncoder *st;
+ if ((channels>255) || (channels<1))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ size = opus_multistream_surround_encoder_init(NULL, Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
+ if (size < 0)
+ {
+ if (error)
+ *error = size;
+ return NULL;
+ }
+ st = (OpusMSEncoder *)opus_alloc(size);
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+
+static void surround_rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size,
+ opus_int32 Fs
+ )
+{
+ int i;
+ opus_int32 channel_rate;
+ int stream_offset;
+ int lfe_offset;
+ int coupled_ratio; /* Q8 */
+ int lfe_ratio; /* Q8 */
+ int nb_lfe;
+ int nb_uncoupled;
+ int nb_coupled;
+ int nb_normal;
+ opus_int32 channel_offset;
+ opus_int32 bitrate;
+ int total;
+
+ nb_lfe = (st->lfe_stream!=-1);
+ nb_coupled = st->layout.nb_coupled_streams;
+ nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
+ nb_normal = 2*nb_coupled + nb_uncoupled;
+
+ /* Give each non-LFE channel enough bits per channel for coding band energy. */
+ channel_offset = 40*IMAX(50, Fs/frame_size);
+
+ if (st->bitrate_bps==OPUS_AUTO)
+ {
+ bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe;
+ } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+ {
+ bitrate = nb_normal*750000 + nb_lfe*128000;
+ } else {
+ bitrate = st->bitrate_bps;
+ }
+
+ /* Give LFE some basic stream_channel allocation but never exceed 1/20 of the
+ total rate for the non-energy part to avoid problems at really low rate. */
+ lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size);
+
+ /* We give each stream (coupled or uncoupled) a starting bitrate.
+ This models the main saving of coupled channels over uncoupled. */
+ stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2;
+ stream_offset = IMAX(0, IMIN(20000, stream_offset));
+
+ /* Coupled streams get twice the mono rate after the offset is allocated. */
+ coupled_ratio = 512;
+ /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
+ lfe_ratio = 32;
+
+ total = (nb_uncoupled<<8) /* mono */
+ + coupled_ratio*nb_coupled /* stereo */
+ + nb_lfe*lfe_ratio;
+ channel_rate = 256*(opus_int64)(bitrate - lfe_offset*nb_lfe - stream_offset*(nb_coupled+nb_uncoupled) - channel_offset*nb_normal)/total;
+
+ for (i=0;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));
+ else if (i!=st->lfe_stream)
+ rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate);
+ else
+ rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8));
+ }
+}
+
+static void ambisonics_rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size,
+ opus_int32 Fs
+ )
+{
+ int i;
+ opus_int32 total_rate;
+ opus_int32 per_stream_rate;
+
+ const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
+
+ if (st->bitrate_bps==OPUS_AUTO)
+ {
+ total_rate = (st->layout.nb_coupled_streams + st->layout.nb_streams) *
+ (Fs+60*Fs/frame_size) + st->layout.nb_streams * (opus_int32)15000;
+ } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+ {
+ total_rate = nb_channels * 750000;
+ } else
+ {
+ total_rate = st->bitrate_bps;
+ }
+
+ /* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic
+ * (coupled) streams */
+ per_stream_rate = total_rate / st->layout.nb_streams;
+ for (i = 0; i < st->layout.nb_streams; i++)
+ {
+ rate[i] = per_stream_rate;
+ }
+}
+
+static opus_int32 rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size
+ )
+{
+ int i;
+ opus_int32 rate_sum=0;
+ opus_int32 Fs;
+ char *ptr;
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+
+ if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
+ ambisonics_rate_allocation(st, rate, frame_size, Fs);
+ } else
+ {
+ surround_rate_allocation(st, rate, frame_size, Fs);
+ }
+
+ for (i=0;i<st->layout.nb_streams;i++)
+ {
+ rate[i] = IMAX(rate[i], 500);
+ rate_sum += rate[i];
+ }
+ return rate_sum;
+}
+
+/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */
+#ifdef ENABLE_QEXT
+#define MS_FRAME_TMP (6*QEXT_PACKET_SIZE_CAP+12)
+#else
+#define MS_FRAME_TMP (6*1275+12)
+#endif
+
+int opus_multistream_encode_native
+(
+ OpusMSEncoder *st,
+ opus_copy_channel_in_func copy_channel_in,
+ const void *pcm,
+ int analysis_frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes,
+ int lsb_depth,
+ downmix_func downmix,
+ int float_api,
+ void *user_data
+)
+{
+ opus_int32 Fs;
+ int coupled_size;
+ int mono_size;
+ int s;
+ char *ptr;
+ int tot_size;
+ VARDECL(opus_res, buf);
+ VARDECL(celt_glog, bandSMR);
+ unsigned char tmp_data[MS_FRAME_TMP];
+ OpusRepacketizer rp;
+ opus_int32 vbr;
+ const CELTMode *celt_mode=NULL;
+ opus_int32 bitrates[256];
+ celt_glog bandLogE[42];
+ opus_val32 *mem = NULL;
+ opus_val32 *preemph_mem=NULL;
+ int frame_size;
+ opus_int32 rate_sum;
+ opus_int32 smallest_packet;
+ ALLOC_STACK;
+
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ preemph_mem = ms_get_preemph_mem(st);
+ mem = ms_get_window_mem(st);
+ }
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr));
+ if (st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
+
+ frame_size = frame_size_select(st->application, analysis_frame_size, st->variable_duration, Fs);
+ if (frame_size <= 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ /* Smallest packet the encoder can produce. */
+ smallest_packet = st->layout.nb_streams*2-1;
+ /* 100 ms needs an extra byte per stream for the ToC. */
+ if (Fs/frame_size == 10)
+ smallest_packet += st->layout.nb_streams;
+ if (max_data_bytes < smallest_packet)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ ALLOC(buf, 2*frame_size, opus_res);
+ coupled_size = opus_encoder_init(NULL, st->Fs, 2, st->application);
+ mono_size = opus_encoder_init(NULL, st->Fs, 1, st->application);
+
+ ALLOC(bandSMR, 21*st->layout.nb_channels, celt_glog);
+ if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, celt_mode->overlap, st->layout.nb_channels, Fs, copy_channel_in, st->arch);
+ }
+
+ /* Compute bitrate allocation between streams (this could be a lot better) */
+ rate_sum = rate_allocation(st, bitrates, frame_size);
+
+ if (!vbr)
+ {
+ if (st->bitrate_bps == OPUS_AUTO)
+ {
+ max_data_bytes = IMIN(max_data_bytes, (bitrate_to_bits(rate_sum, Fs, frame_size)+4)/8);
+ } else if (st->bitrate_bps != OPUS_BITRATE_MAX)
+ {
+ max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet,
+ (bitrate_to_bits(st->bitrate_bps, Fs, frame_size)+4)/8));
+ }
+ }
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ opus_int32 equiv_rate;
+ equiv_rate = st->bitrate_bps;
+ if (frame_size*50 < Fs)
+ equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels;
+ if (equiv_rate > 10000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ else if (equiv_rate > 7000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+ else if (equiv_rate > 5000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+ else
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
+ if (s < st->layout.nb_coupled_streams)
+ {
+ /* To preserve the spatial image, force stereo CELT on coupled streams */
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
+ }
+ }
+ else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+ }
+ }
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ /* Counting ToC */
+ tot_size = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ int len;
+ int curr_max;
+ int c1, c2;
+ int ret;
+
+ opus_repacketizer_init(&rp);
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ {
+ int i;
+ int left, right;
+ left = get_left_channel(&st->layout, s, -1);
+ right = get_right_channel(&st->layout, s, -1);
+ (*copy_channel_in)(buf, 2,
+ pcm, st->layout.nb_channels, left, frame_size, user_data);
+ (*copy_channel_in)(buf+1, 2,
+ pcm, st->layout.nb_channels, right, frame_size, user_data);
+ ptr += align(coupled_size);
+ if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ for (i=0;i<21;i++)
+ {
+ bandLogE[i] = bandSMR[21*left+i];
+ bandLogE[21+i] = bandSMR[21*right+i];
+ }
+ }
+ c1 = left;
+ c2 = right;
+ } else {
+ int i;
+ int chan = get_mono_channel(&st->layout, s, -1);
+ (*copy_channel_in)(buf, 1,
+ pcm, st->layout.nb_channels, chan, frame_size, user_data);
+ ptr += align(mono_size);
+ if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ {
+ for (i=0;i<21;i++)
+ bandLogE[i] = bandSMR[21*chan+i];
+ }
+ c1 = chan;
+ c2 = -1;
+ }
+ if (st->mapping_type == MAPPING_TYPE_SURROUND && st->application != OPUS_APPLICATION_RESTRICTED_SILK)
+ opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
+ /* number of bytes left (+Toc) */
+ curr_max = max_data_bytes - tot_size;
+ /* Reserve one byte for the last stream and two for the others */
+ curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1);
+ /* For 100 ms, reserve an extra byte per stream for the ToC */
+ if (Fs/frame_size == 10)
+ curr_max -= st->layout.nb_streams-s-1;
+ curr_max = IMIN(curr_max,MS_FRAME_TMP);
+ /* Repacketizer will add one or two bytes for self-delimited frames */
+ if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1;
+ if (!vbr && s == st->layout.nb_streams-1)
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bits_to_bitrate(curr_max*8, Fs, frame_size)));
+ len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth,
+ pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api);
+ if (len<0)
+ {
+ RESTORE_STACK;
+ return len;
+ }
+ /* We need to use the repacketizer to add the self-delimiting lengths
+ while taking into account the fact that the encoder can now return
+ more than one frame at a time (e.g. 60 ms CELT-only) */
+ ret = opus_repacketizer_cat(&rp, tmp_data, len);
+ /* If the opus_repacketizer_cat() fails, then something's seriously wrong
+ with the encoder. */
+ if (ret != OPUS_OK)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp),
+ data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1, NULL, 0);
+ data += len;
+ tot_size += len;
+ }
+ /*printf("\n");*/
+ RESTORE_STACK;
+ return tot_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_in_float(
+ opus_res *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size,
+ void *user_data
+)
+{
+ const float *float_src;
+ opus_int32 i;
+ (void)user_data;
+ float_src = (const float *)src;
+ for (i=0;i<frame_size;i++)
+ dst[i*dst_stride] = FLOAT2RES(float_src[i*src_stride+src_channel]);
+}
+#endif
+
+static void opus_copy_channel_in_short(
+ opus_res *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size,
+ void *user_data
+)
+{
+ const opus_int16 *short_src;
+ opus_int32 i;
+ (void)user_data;
+ short_src = (const opus_int16 *)src;
+ for (i=0;i<frame_size;i++)
+ dst[i*dst_stride] = INT16TORES(short_src[i*src_stride+src_channel]);
+}
+
+static void opus_copy_channel_in_int24(
+ opus_res *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size,
+ void *user_data
+)
+{
+ const opus_int32 *short_src;
+ opus_int32 i;
+ (void)user_data;
+ short_src = (const opus_int32 *)src;
+ for (i=0;i<frame_size;i++)
+ dst[i*dst_stride] = INT24TORES(short_src[i*src_stride+src_channel]);
+}
+
+int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL);
+}
+
+int opus_multistream_encode24(
+ OpusMSEncoder *st,
+ const opus_int32 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_int24,
+ pcm, frame_size, data, max_data_bytes, MAX_ENCODING_DEPTH, downmix_int24, 0, NULL);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes, MAX_ENCODING_DEPTH, downmix_float, 1, NULL);
+}
+#endif
+
+int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request,
+ va_list ap)
+{
+ int coupled_size, mono_size;
+ char *ptr;
+ int ret = OPUS_OK;
+
+ coupled_size = opus_encoder_init(NULL, st->Fs, 2, st->application);
+ mono_size = opus_encoder_init(NULL, st->Fs, 1, st->application);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ switch (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)
+ goto bad_arg;
+ value = IMIN(750000*st->layout.nb_channels, IMAX(500*st->layout.nb_channels, value));
+ }
+ st->bitrate_bps = value;
+ }
+ break;
+ case OPUS_GET_BITRATE_REQUEST:
+ {
+ int s;
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ opus_int32 rate;
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ opus_encoder_ctl(enc, request, &rate);
+ *value += rate;
+ }
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ case OPUS_GET_VBR_REQUEST:
+ case OPUS_GET_APPLICATION_REQUEST:
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ case OPUS_GET_COMPLEXITY_REQUEST:
+ case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+ case OPUS_GET_DTX_REQUEST:
+ case OPUS_GET_VOICE_RATIO_REQUEST:
+ case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_GET_SIGNAL_REQUEST:
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ case OPUS_GET_INBAND_FEC_REQUEST:
+ case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+ case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
+ case OPUS_GET_QEXT_REQUEST:
+ {
+ OpusEncoder *enc;
+ /* For int32* GET params, just query the first stream */
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ enc = (OpusEncoder*)ptr;
+ ret = opus_encoder_ctl(enc, request, value);
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ int s;
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ opus_uint32 tmp;
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value=0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, request, &tmp);
+ if (ret != OPUS_OK) break;
+ *value ^= tmp;
+ }
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ case OPUS_SET_VBR_REQUEST:
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+ case OPUS_SET_BANDWIDTH_REQUEST:
+ case OPUS_SET_SIGNAL_REQUEST:
+ case OPUS_SET_APPLICATION_REQUEST:
+ case OPUS_SET_INBAND_FEC_REQUEST:
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ case OPUS_SET_DTX_REQUEST:
+ case OPUS_SET_FORCE_MODE_REQUEST:
+ case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+ case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
+ case OPUS_SET_QEXT_REQUEST:
+ {
+ int s;
+ /* This works for int32 params */
+ opus_int32 value = va_arg(ap, opus_int32);
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, request, value);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
+ {
+ int s;
+ opus_int32 stream_id;
+ OpusEncoder **value;
+ stream_id = va_arg(ap, opus_int32);
+ if (stream_id<0 || stream_id >= st->layout.nb_streams)
+ goto bad_arg;
+ value = va_arg(ap, OpusEncoder**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ for (s=0;s<stream_id;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ *value = (OpusEncoder*)ptr;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->variable_duration = value;
+ }
+ break;
+ case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->variable_duration;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int s;
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
+ OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*MAX_OVERLAP);
+ }
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, OPUS_RESET_STATE);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ default:
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+ return ret;
+bad_arg:
+ return OPUS_BAD_ARG;
+}
+
+int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, request);
+ ret = opus_multistream_encoder_ctl_va_list(st, request, ap);
+ va_end(ap);
+ return ret;
+}
+
+void opus_multistream_encoder_destroy(OpusMSEncoder *st)
+{
+ opus_free(st);
+}
--- /dev/null
+/* 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_res *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_res *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 void opus_projection_copy_channel_in_int24(
+ opus_res *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size,
+ void *user_data
+)
+{
+ mapping_matrix_multiply_channel_in_int24((const MappingMatrix*)user_data,
+ (const opus_int32*)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 if (order_plus_one == 5)
+ {
+ mixing_matrix_rows = mapping_matrix_fourthoa_mixing.rows;
+ mixing_matrix_cols = mapping_matrix_fourthoa_mixing.cols;
+ demixing_matrix_rows = mapping_matrix_fourthoa_demixing.rows;
+ demixing_matrix_cols = mapping_matrix_fourthoa_demixing.cols;
+ }
+ else if (order_plus_one == 6)
+ {
+ mixing_matrix_rows = mapping_matrix_fifthoa_mixing.rows;
+ mixing_matrix_cols = mapping_matrix_fifthoa_mixing.cols;
+ demixing_matrix_rows = mapping_matrix_fifthoa_demixing.rows;
+ demixing_matrix_cols = mapping_matrix_fifthoa_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 if (order_plus_one == 5)
+ {
+ mapping_matrix_init(mixing_matrix, mapping_matrix_fourthoa_mixing.rows,
+ mapping_matrix_fourthoa_mixing.cols, mapping_matrix_fourthoa_mixing.gain,
+ mapping_matrix_fourthoa_mixing_data,
+ sizeof(mapping_matrix_fourthoa_mixing_data));
+ }
+ else if (order_plus_one == 6)
+ {
+ mapping_matrix_init(mixing_matrix, mapping_matrix_fifthoa_mixing.rows,
+ mapping_matrix_fifthoa_mixing.cols, mapping_matrix_fifthoa_mixing.gain,
+ mapping_matrix_fifthoa_mixing_data,
+ sizeof(mapping_matrix_fifthoa_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 if (order_plus_one == 5)
+ {
+ mapping_matrix_init(demixing_matrix, mapping_matrix_fourthoa_demixing.rows,
+ mapping_matrix_fourthoa_demixing.cols, mapping_matrix_fourthoa_demixing.gain,
+ mapping_matrix_fourthoa_demixing_data,
+ sizeof(mapping_matrix_fourthoa_demixing_data));
+ }
+ else if (order_plus_one == 6)
+ {
+ mapping_matrix_init(demixing_matrix, mapping_matrix_fifthoa_demixing.rows,
+ mapping_matrix_fifthoa_demixing.cols, mapping_matrix_fifthoa_demixing.gain,
+ mapping_matrix_fifthoa_demixing_data,
+ sizeof(mapping_matrix_fifthoa_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));
+}
+
+int opus_projection_encode24(OpusProjectionEncoder *st, const opus_int32 *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_int24, pcm, frame_size, data,
+ max_data_bytes, MAX_ENCODING_DEPTH, downmix_int, 0, get_mixing_matrix(st));
+}
+
+#ifndef DISABLE_FLOAT_API
+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, MAX_ENCODING_DEPTH, downmix_float, 1, get_mixing_matrix(st));
+}
+#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;
+}