diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d8460ff --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,39 @@ +name: Wails build + +on: + push: + tags: + # Match any new tag + - '*' + +env: + # Necessary for most environments as build failure can occur due to OOM issues + NODE_OPTIONS: "--max-old-space-size=4096" + +jobs: + build: + strategy: + # Failure in one platform build won't impact the others + fail-fast: false + matrix: + build: + - name: 'wechatDataBackup.exe' + platform: 'windows/amd64' + os: 'windows-latest' + + runs-on: ${{ matrix.build.os }} + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Build wails + uses: dAppServer/wails-build-action@v2.2 + id: build + with: + build-name: ${{ matrix.build.name }} + sign: false + build-platform: ${{ matrix.build.platform }} + package: true + go-version: '1.21' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07196c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# After editing .gitignore to match the ignored files, you can do < git ls-files -ci --exclude-standard > +# to see the files that are included in the exclude lists; you can then do +# +# @ Linux/MacOS: < git ls-files -ci --exclude-standard -z | xargs -0 git rm --cached > +# @ Windows (PowerShell): < git ls-files -ci --exclude-standard | % { git rm --cached "$_" } > +# @ Windows (cmd.exe): < for /F "tokens=*" %a in ('git ls-files -ci --exclude-standard') do @git rm --cached "%a" > +# ...to re-init the ignore list + +# Wails directories +build/bin +frontend/wailsjs +frontend/node_modules + +# Wails junk files +.syso + +# Go files +go.sum + +# IDEs +.idea +.vscode + +# System enviroment variables +env +*/.DS_Store + + +# runtime +User +config.json +wechatDataBackup.exe +app.log \ No newline at end of file diff --git a/README.md b/README.md index 2fd0eaa..7399fdd 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,68 @@ # wechatDataBackup PC微信聊天记录数据导出工具 + +* 基于wails开发 + React前端,实现PC端微信聊天记录一键导出功能。 +* 导出后数据可以做永久化保存,即使微信停止支持,聊天记录也可以随时查看。 +* 前端界面尽量与微信界面保持一致,减少使用成本。 +* 理论上支持所有Windows 32/64位微信版本。 + +效果图如下: + +![](./res/result.png) + +## 使用方法 +1. 下载release可执行文件直接打开 +2. 下载源码自行编译可执行文件 [安装wails环境](https://wails.io/zh-Hans/docs/gettingstarted/installation) +```shell +git clone https://github.com/git-jiadong/wechatDataBackup.git +cd wechatDataBackup +wails build +``` +编译成功后在可执行二进制文件路径`build\bin\wechatDataBackup.exe` + +3. 导出聊天记录 +电脑登陆微信,然后打开`wechatDataBackup.exe`后按照如图提示导出 +![](./res/tips.png) + +## 功能 +本项目目前的规划与实现进度: +- [x] 支持图片消息 +- [x] 支持视频消息 +- [x] 支持链接消息 +- [x] 支持文件消息 +- [x] 支持原始表情显示 +- [x] 支持按类型检索 +- [x] 支持日期检索 +- [x] 支持按群成员检索 +- [x] 支持增量式导出 +- [ ] 支持更多消息类型显示 +- [ ] 图片查看器重绘 +- [ ] 实现头像或表情预先下载(实现完全离线查看) +- [ ] 聊天报告 +- [ ] AI本地模型应用 +- [ ] 导出数据本地加密 +- ... +如果遇到什么问题,或者有更好的建议与优化点欢迎给作者提 [ISSUE](https://github.com/git-jiadong/wechatDataBackup/issues) + + +### 常见问题 +Q: 支持手机端的聊天记录备份吗?
+A: 手机端可以使用聊天数据迁移功能,将手机的数据迁移到电脑后再将数据导出 [迁移聊天记录](https://mp.weixin.qq.com/s?src=11×tamp=1724572247&ver=5465&signature=j1TNxZAx48TdBzc6KJIHInIvXlBhwSAlQ4XGowKeyijZ2gsmXyOb2Zpg9qfVyMdGrte0SwU9kT8xCDgFBI7CR7fqCHpHuZzpv3O77gSkV3mbxmFdPKfW7Fq89CzHPQr0&new=1)
+Q: 导出的数据比PC微信里面看到的少,数据不完整
+A: 这是由于可能数据存在于内存中还没有回写到磁盘导致的,退出微信时会将内存的数据全部回写到磁盘,导出数据时最好退出重新登陆一次微信,保证数据都在磁盘中再导出即可。
+ +## 免责声明 +**⚠️ 本项目仅供学习、研究使用,严禁商业使用**
+**⚠️ 用于网络安全用途的,请确保在国家法律法规下使用**
+**⚠️ 本项目完全免费,问你要钱的都是骗子**
+**⚠️ 使用本项目初衷是作者研究微信数据库的运行使用,您使用本软件导致的后果,包含但不限于数据损坏,记录丢失等问题,作者不承担相关责任。**
+**⚠️ 因软件特殊性质,请在使用时获得微信账号所有人授权,你当确保不侵犯他人个人隐私权,后果自行承担**
+ +## 前端代码 +由于前端代码不成熟,前端界面代码暂时不公开。 + +## 参考/引用 +- 微信数据库解密和数据库的使用 [PyWxDump](https://github.com/xaoyaoo/PyWxDump/tree/master) +- silk语音消息解码 [silk-v3-decoder](https://github.com/kn007/silk-v3-decoder) +- PCM转MP3 [lame](https://github.com/viert/lame.git) +- Dat图片解码 [wechatDatDecode](https://github.com/liuggchen/wechatDatDecode) \ No newline at end of file diff --git a/app.go b/app.go new file mode 100644 index 0000000..648b4a7 --- /dev/null +++ b/app.go @@ -0,0 +1,304 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + "wechatDataBackup/pkg/utils" + "wechatDataBackup/pkg/wechat" + + "github.com/spf13/viper" + "github.com/wailsapp/wails/v2/pkg/runtime" +) + +const ( + defaultConfig = "config" + configDefaultUserKey = "userConfig.defaultUser" + configUsersKey = "userConfig.users" + appVersion = "v1.0.0" +) + +// App struct +type App struct { + ctx context.Context + info wechat.WeChatInfo + provider *wechat.WechatDataProvider + defaultUser string + users []string +} + +type WeChatInfo struct { + ProcessID uint32 `json:"PID"` + FilePath string `json:"FilePath"` + AcountName string `json:"AcountName"` + Version string `json:"Version"` + Is64Bits bool `json:"Is64Bits"` + DBKey string `json:"DBkey"` +} + +// NewApp creates a new App application struct +func NewApp() *App { + a := &App{} + + viper.SetConfigName(defaultConfig) + viper.SetConfigType("json") + viper.AddConfigPath(".") + if err := viper.ReadInConfig(); err == nil { + a.defaultUser = viper.GetString(configDefaultUserKey) + a.users = viper.GetStringSlice(configUsersKey) + // log.Println(a.defaultUser) + // log.Println(a.users) + } else { + log.Println("not config exist") + } + + return a +} + +// startup is called when the app starts. The context is saved +// so we can call the runtime methods +func (a *App) startup(ctx context.Context) { + a.ctx = ctx +} + +func (a *App) beforeClose(ctx context.Context) (prevent bool) { + dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{ + Type: runtime.QuestionDialog, + Title: "Quit?", + Message: "Are you sure you want to quit?", + }) + + if err != nil || dialog == "Yes" { + a.provider.WechatWechatDataProviderClose() + a.provider = nil + return false + } + + return true +} + +func (a *App) GetWeChatAllInfo() string { + a.info, _ = wechat.GetWeChatAllInfo() + + var info WeChatInfo + info.ProcessID = a.info.ProcessID + info.FilePath = a.info.FilePath + info.AcountName = a.info.AcountName + info.Version = a.info.Version + info.Is64Bits = a.info.Is64Bits + info.DBKey = a.info.DBKey + + infoStr, _ := json.Marshal(info) + log.Println(string(infoStr)) + + return string(infoStr) +} + +func (a *App) ExportWeChatAllData(full bool) { + + if a.provider != nil { + a.provider.WechatWechatDataProviderClose() + a.provider = nil + } + + progress := make(chan string) + go func() { + + _, err := os.Stat(".\\User") + if err != nil { + os.Mkdir(".\\User", os.ModeDir) + } + + expPath := ".\\User\\" + a.info.AcountName + _, err = os.Stat(expPath) + if err == nil { + if !full { + os.RemoveAll(expPath + "\\Msg") + } else { + os.RemoveAll(expPath) + } + } + + _, err = os.Stat(expPath) + if err != nil { + os.Mkdir(expPath, os.ModeDir) + } + + go wechat.ExportWeChatAllData(a.info, expPath, progress) + + for p := range progress { + log.Println(p) + runtime.EventsEmit(a.ctx, "exportData", p) + } + + if len(a.defaultUser) == 0 { + a.defaultUser = a.info.AcountName + } + + hasUser := false + for _, user := range a.users { + if user == a.info.AcountName { + hasUser = true + break + } + } + if !hasUser { + a.users = append(a.users, a.info.AcountName) + } + a.setCurrentConfig() + }() +} + +func (a *App) createWechatDataProvider(resPath string) error { + if a.provider != nil && a.provider.SelfInfo != nil && filepath.Base(resPath) == a.provider.SelfInfo.UserName { + log.Println("WechatDataProvider not need create:", a.provider.SelfInfo.UserName) + return nil + } + + provider, err := wechat.CreateWechatDataProvider(resPath) + if err != nil { + log.Println("CreateWechatDataProvider failed:", resPath) + return err + } + + a.provider = provider + // infoJson, _ := json.Marshal(a.provider.SelfInfo) + // runtime.EventsEmit(a.ctx, "selfInfo", string(infoJson)) + return nil +} + +func (a *App) WeChatInit() { + expPath := ".\\User\\" + a.defaultUser + if a.createWechatDataProvider(expPath) == nil { + infoJson, _ := json.Marshal(a.provider.SelfInfo) + runtime.EventsEmit(a.ctx, "selfInfo", string(infoJson)) + } +} + +func (a *App) GetWechatSessionList(pageIndex int, pageSize int) string { + expPath := ".\\User\\" + a.defaultUser + if a.createWechatDataProvider(expPath) != nil { + return "" + } + log.Printf("pageIndex: %d\n", pageIndex) + list, err := a.provider.WeChatGetSessionList(pageIndex, pageSize) + if err != nil { + return "" + } + + listStr, _ := json.Marshal(list) + log.Println("GetWechatSessionList:", list.Total) + return string(listStr) +} + +func (a *App) GetWechatMessageListByTime(userName string, time int64, pageSize int, direction string) string { + log.Println("GetWechatMessageList:", userName, pageSize, time, direction) + if len(userName) == 0 { + return "{\"Total\":0, \"Rows\":[]}" + } + dire := wechat.Message_Search_Forward + if direction == "backward" { + dire = wechat.Message_Search_Backward + } else if direction == "both" { + dire = wechat.Message_Search_Both + } + list, err := a.provider.WeChatGetMessageListByTime(userName, time, pageSize, dire) + if err != nil { + log.Println("WeChatGetMessageList failed:", err) + return "" + } + listStr, _ := json.Marshal(list) + log.Println("GetWechatMessageList:", list.Total) + + return string(listStr) +} + +func (a *App) GetWechatMessageListByKeyWord(userName string, time int64, keyword string, msgType string, pageSize int) string { + log.Println("GetWechatMessageListByKeyWord:", userName, pageSize, time, msgType) + if len(userName) == 0 { + return "{\"Total\":0, \"Rows\":[]}" + } + list, err := a.provider.WeChatGetMessageListByKeyWord(userName, time, keyword, msgType, pageSize) + if err != nil { + log.Println("WeChatGetMessageListByKeyWord failed:", err) + return "" + } + listStr, _ := json.Marshal(list) + log.Println("WeChatGetMessageListByKeyWord:", list.Total, list.KeyWord) + + return string(listStr) +} + +func (a *App) GetWechatMessageDate(userName string) string { + log.Println("GetWechatMessageDate:", userName) + if len(userName) == 0 { + return "{\"Total\":0, \"Date\":[]}" + } + + messageData, err := a.provider.WeChatGetMessageDate(userName) + if err != nil { + log.Println("GetWechatMessageDate:", err) + return "" + } + + messageDataStr, _ := json.Marshal(messageData) + log.Println("GetWechatMessageDate:", messageData.Total) + + return string(messageDataStr) +} + +func (a *App) setCurrentConfig() { + viper.Set(configDefaultUserKey, a.defaultUser) + viper.Set(configUsersKey, a.users) + err := viper.SafeWriteConfig() + if err != nil { + log.Println(err) + } +} + +type userList struct { + Users []string `json:"Users"` +} + +func (a *App) GetWeChatUserList() string { + + l := userList{} + l.Users = a.users + + usersStr, _ := json.Marshal(l) + str := string(usersStr) + log.Println("users:", str) + return str +} + +func (a *App) OpenFileOrExplorer(filePath string, explorer bool) string { + // if root, err := os.Getwd(); err == nil { + // filePath = root + filePath[1:] + // } + // log.Println("OpenFileOrExplorer:", filePath) + err := utils.OpenFileOrExplorer(filePath, explorer) + if err != nil { + return "{\"result\": \"OpenFileOrExplorer failed\", \"status\":\"failed\"}" + } + + return fmt.Sprintf("{\"result\": \"%s\", \"status\":\"OK\"}", "") +} + +func (a *App) GetWeChatRoomUserList(roomId string) string { + userlist, err := a.provider.WeChatGetChatRoomUserList(roomId) + if err != nil { + log.Println("WeChatGetChatRoomUserList:", err) + return "" + } + + userListStr, _ := json.Marshal(userlist) + + return string(userListStr) +} + +func (a *App) GetAppVersion() string { + return appVersion +} diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..1ae2f67 --- /dev/null +++ b/build/README.md @@ -0,0 +1,35 @@ +# Build Directory + +The build directory is used to house all the build files and assets for your application. + +The structure is: + +* bin - Output directory +* darwin - macOS specific files +* windows - Windows specific files + +## Mac + +The `darwin` directory holds files specific to Mac builds. +These may be customised and used as part of the build. To return these files to the default state, simply delete them +and +build with `wails build`. + +The directory contains the following files: + +- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. +- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. + +## Windows + +The `windows` directory contains the manifest and rc files used when building with `wails build`. +These may be customised for your application. To return these files to the default state, simply delete them and +build with `wails build`. + +- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to + use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file + will be created using the `appicon.png` file in the build directory. +- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. +- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, + as well as the application itself (right click the exe -> properties -> details) +- `wails.exe.manifest` - The main application manifest file. \ No newline at end of file diff --git a/build/appicon.png b/build/appicon.png new file mode 100644 index 0000000..d0e5563 Binary files /dev/null and b/build/appicon.png differ diff --git a/build/darwin/Info.dev.plist b/build/darwin/Info.dev.plist new file mode 100644 index 0000000..04727c2 --- /dev/null +++ b/build/darwin/Info.dev.plist @@ -0,0 +1,68 @@ + + + + CFBundlePackageType + APPL + CFBundleName + {{.Info.ProductName}} + CFBundleExecutable + {{.Name}} + CFBundleIdentifier + com.wails.{{.Name}} + CFBundleVersion + {{.Info.ProductVersion}} + CFBundleGetInfoString + {{.Info.Comments}} + CFBundleShortVersionString + {{.Info.ProductVersion}} + CFBundleIconFile + iconfile + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + {{.Info.Copyright}} + {{if .Info.FileAssociations}} + CFBundleDocumentTypes + + {{range .Info.FileAssociations}} + + CFBundleTypeExtensions + + {{.Ext}} + + CFBundleTypeName + {{.Name}} + CFBundleTypeRole + {{.Role}} + CFBundleTypeIconFile + {{.IconName}} + + {{end}} + + {{end}} + {{if .Info.Protocols}} + CFBundleURLTypes + + {{range .Info.Protocols}} + + CFBundleURLName + com.wails.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + CFBundleTypeRole + {{.Role}} + + {{end}} + + {{end}} + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + + diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist new file mode 100644 index 0000000..19cc937 --- /dev/null +++ b/build/darwin/Info.plist @@ -0,0 +1,63 @@ + + + + CFBundlePackageType + APPL + CFBundleName + {{.Info.ProductName}} + CFBundleExecutable + {{.Name}} + CFBundleIdentifier + com.wails.{{.Name}} + CFBundleVersion + {{.Info.ProductVersion}} + CFBundleGetInfoString + {{.Info.Comments}} + CFBundleShortVersionString + {{.Info.ProductVersion}} + CFBundleIconFile + iconfile + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + {{.Info.Copyright}} + {{if .Info.FileAssociations}} + CFBundleDocumentTypes + + {{range .Info.FileAssociations}} + + CFBundleTypeExtensions + + {{.Ext}} + + CFBundleTypeName + {{.Name}} + CFBundleTypeRole + {{.Role}} + CFBundleTypeIconFile + {{.IconName}} + + {{end}} + + {{end}} + {{if .Info.Protocols}} + CFBundleURLTypes + + {{range .Info.Protocols}} + + CFBundleURLName + com.wails.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + CFBundleTypeRole + {{.Role}} + + {{end}} + + {{end}} + + diff --git a/build/windows/icon.ico b/build/windows/icon.ico new file mode 100644 index 0000000..b0afe8e Binary files /dev/null and b/build/windows/icon.ico differ diff --git a/build/windows/info.json b/build/windows/info.json new file mode 100644 index 0000000..9727946 --- /dev/null +++ b/build/windows/info.json @@ -0,0 +1,15 @@ +{ + "fixed": { + "file_version": "{{.Info.ProductVersion}}" + }, + "info": { + "0000": { + "ProductVersion": "{{.Info.ProductVersion}}", + "CompanyName": "{{.Info.CompanyName}}", + "FileDescription": "{{.Info.ProductName}}", + "LegalCopyright": "{{.Info.Copyright}}", + "ProductName": "{{.Info.ProductName}}", + "Comments": "{{.Info.Comments}}" + } + } +} \ No newline at end of file diff --git a/build/windows/installer/project.nsi b/build/windows/installer/project.nsi new file mode 100644 index 0000000..654ae2e --- /dev/null +++ b/build/windows/installer/project.nsi @@ -0,0 +1,114 @@ +Unicode true + +#### +## Please note: Template replacements don't work in this file. They are provided with default defines like +## mentioned underneath. +## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. +## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually +## from outside of Wails for debugging and development of the installer. +## +## For development first make a wails nsis build to populate the "wails_tools.nsh": +## > wails build --target windows/amd64 --nsis +## Then you can call makensis on this file with specifying the path to your binary: +## For a AMD64 only installer: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe +## For a ARM64 only installer: +## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe +## For a installer with both architectures: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe +#### +## The following information is taken from the ProjectInfo file, but they can be overwritten here. +#### +## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" +## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" +## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" +## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" +## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" +### +## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" +## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +#### +## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html +#### +## Include the wails tools +#### +!include "wails_tools.nsh" + +# The version information for this two must consist of 4 parts +VIProductVersion "${INFO_PRODUCTVERSION}.0" +VIFileVersion "${INFO_PRODUCTVERSION}.0" + +VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" +VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" +VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" +VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" + +# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware +ManifestDPIAware true + +!include "MUI.nsh" + +!define MUI_ICON "..\icon.ico" +!define MUI_UNICON "..\icon.ico" +# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 +!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps +!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. + +!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. +# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer +!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. +!insertmacro MUI_PAGE_INSTFILES # Installing page. +!insertmacro MUI_PAGE_FINISH # Finished installation page. + +!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page + +!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer + +## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 +#!uninstfinalize 'signtool --file "%1"' +#!finalize 'signtool --file "%1"' + +Name "${INFO_PRODUCTNAME}" +OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. +InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). +ShowInstDetails show # This will always show the installation details. + +Function .onInit + !insertmacro wails.checkArchitecture +FunctionEnd + +Section + !insertmacro wails.setShellContext + + !insertmacro wails.webview2runtime + + SetOutPath $INSTDIR + + !insertmacro wails.files + + CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + + !insertmacro wails.associateFiles + !insertmacro wails.associateCustomProtocols + + !insertmacro wails.writeUninstaller +SectionEnd + +Section "uninstall" + !insertmacro wails.setShellContext + + RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath + + RMDir /r $INSTDIR + + Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" + Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" + + !insertmacro wails.unassociateFiles + !insertmacro wails.unassociateCustomProtocols + + !insertmacro wails.deleteUninstaller +SectionEnd diff --git a/build/windows/installer/wails_tools.nsh b/build/windows/installer/wails_tools.nsh new file mode 100644 index 0000000..f9c0f88 --- /dev/null +++ b/build/windows/installer/wails_tools.nsh @@ -0,0 +1,249 @@ +# DO NOT EDIT - Generated automatically by `wails build` + +!include "x64.nsh" +!include "WinVer.nsh" +!include "FileFunc.nsh" + +!ifndef INFO_PROJECTNAME + !define INFO_PROJECTNAME "{{.Name}}" +!endif +!ifndef INFO_COMPANYNAME + !define INFO_COMPANYNAME "{{.Info.CompanyName}}" +!endif +!ifndef INFO_PRODUCTNAME + !define INFO_PRODUCTNAME "{{.Info.ProductName}}" +!endif +!ifndef INFO_PRODUCTVERSION + !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}" +!endif +!ifndef INFO_COPYRIGHT + !define INFO_COPYRIGHT "{{.Info.Copyright}}" +!endif +!ifndef PRODUCT_EXECUTABLE + !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" +!endif +!ifndef UNINST_KEY_NAME + !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +!endif +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" + +!ifndef REQUEST_EXECUTION_LEVEL + !define REQUEST_EXECUTION_LEVEL "admin" +!endif + +RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" + +!ifdef ARG_WAILS_AMD64_BINARY + !define SUPPORTS_AMD64 +!endif + +!ifdef ARG_WAILS_ARM64_BINARY + !define SUPPORTS_ARM64 +!endif + +!ifdef SUPPORTS_AMD64 + !ifdef SUPPORTS_ARM64 + !define ARCH "amd64_arm64" + !else + !define ARCH "amd64" + !endif +!else + !ifdef SUPPORTS_ARM64 + !define ARCH "arm64" + !else + !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" + !endif +!endif + +!macro wails.checkArchitecture + !ifndef WAILS_WIN10_REQUIRED + !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." + !endif + + !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED + !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" + !endif + + ${If} ${AtLeastWin10} + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + Goto ok + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + Goto ok + ${EndIf} + !endif + + IfSilent silentArch notSilentArch + silentArch: + SetErrorLevel 65 + Abort + notSilentArch: + MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" + Quit + ${else} + IfSilent silentWin notSilentWin + silentWin: + SetErrorLevel 64 + Abort + notSilentWin: + MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" + Quit + ${EndIf} + + ok: +!macroend + +!macro wails.files + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" + ${EndIf} + !endif +!macroend + +!macro wails.writeUninstaller + WriteUninstaller "$INSTDIR\uninstall.exe" + + SetRegView 64 + WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" +!macroend + +!macro wails.deleteUninstaller + Delete "$INSTDIR\uninstall.exe" + + SetRegView 64 + DeleteRegKey HKLM "${UNINST_KEY}" +!macroend + +!macro wails.setShellContext + ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" + SetShellVarContext all + ${else} + SetShellVarContext current + ${EndIf} +!macroend + +# Install webview2 by launching the bootstrapper +# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment +!macro wails.webview2runtime + !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT + !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" + !endif + + SetRegView 64 + # If the admin key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + + ${If} ${REQUEST_EXECUTION_LEVEL} == "user" + # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + ${EndIf} + + SetDetailsPrint both + DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" + SetDetailsPrint listonly + + InitPluginsDir + CreateDirectory "$pluginsdir\webview2bootstrapper" + SetOutPath "$pluginsdir\webview2bootstrapper" + File "tmp\MicrosoftEdgeWebview2Setup.exe" + ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' + + SetDetailsPrint both + ok: +!macroend + +# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" + + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" + + DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` +!macroend + +!macro wails.associateFiles + ; Create file associations + {{range .Info.FileAssociations}} + !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + + File "..\{{.IconName}}.ico" + {{end}} +!macroend + +!macro wails.unassociateFiles + ; Delete app associations + {{range .Info.FileAssociations}} + !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}" + + Delete "$INSTDIR\{{.IconName}}.ico" + {{end}} +!macroend + +!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND + DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" +!macroend + +!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL + DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" +!macroend + +!macro wails.associateCustomProtocols + ; Create custom protocols associations + {{range .Info.Protocols}} + !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + + {{end}} +!macroend + +!macro wails.unassociateCustomProtocols + ; Delete app custom protocol associations + {{range .Info.Protocols}} + !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}" + {{end}} +!macroend diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest new file mode 100644 index 0000000..17e1a23 --- /dev/null +++ b/build/windows/wails.exe.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + true/pm + permonitorv2,permonitor + + + \ No newline at end of file diff --git a/frontend/dist/assets/001_微笑.1ec7a344.png b/frontend/dist/assets/001_微笑.1ec7a344.png new file mode 100644 index 0000000..ab81877 Binary files /dev/null and b/frontend/dist/assets/001_微笑.1ec7a344.png differ diff --git a/frontend/dist/assets/002_撇嘴.0279218b.png b/frontend/dist/assets/002_撇嘴.0279218b.png new file mode 100644 index 0000000..623e454 Binary files /dev/null and b/frontend/dist/assets/002_撇嘴.0279218b.png differ diff --git a/frontend/dist/assets/003_色.e92bb91a.png b/frontend/dist/assets/003_色.e92bb91a.png new file mode 100644 index 0000000..5e89b41 Binary files /dev/null and b/frontend/dist/assets/003_色.e92bb91a.png differ diff --git a/frontend/dist/assets/004_发呆.8d849292.png b/frontend/dist/assets/004_发呆.8d849292.png new file mode 100644 index 0000000..7d52967 Binary files /dev/null and b/frontend/dist/assets/004_发呆.8d849292.png differ diff --git a/frontend/dist/assets/005_得意.72060784.png b/frontend/dist/assets/005_得意.72060784.png new file mode 100644 index 0000000..5de282b Binary files /dev/null and b/frontend/dist/assets/005_得意.72060784.png differ diff --git a/frontend/dist/assets/006_流泪.f52e5f23.png b/frontend/dist/assets/006_流泪.f52e5f23.png new file mode 100644 index 0000000..236c98f Binary files /dev/null and b/frontend/dist/assets/006_流泪.f52e5f23.png differ diff --git a/frontend/dist/assets/007_害羞.414541cc.png b/frontend/dist/assets/007_害羞.414541cc.png new file mode 100644 index 0000000..88c8717 Binary files /dev/null and b/frontend/dist/assets/007_害羞.414541cc.png differ diff --git a/frontend/dist/assets/008_闭嘴.4b6c78a6.png b/frontend/dist/assets/008_闭嘴.4b6c78a6.png new file mode 100644 index 0000000..b568ecc Binary files /dev/null and b/frontend/dist/assets/008_闭嘴.4b6c78a6.png differ diff --git a/frontend/dist/assets/009_睡.75e64219.png b/frontend/dist/assets/009_睡.75e64219.png new file mode 100644 index 0000000..2506f2e Binary files /dev/null and b/frontend/dist/assets/009_睡.75e64219.png differ diff --git a/frontend/dist/assets/010_大哭.2cd2fee3.png b/frontend/dist/assets/010_大哭.2cd2fee3.png new file mode 100644 index 0000000..c0a63c1 Binary files /dev/null and b/frontend/dist/assets/010_大哭.2cd2fee3.png differ diff --git a/frontend/dist/assets/011_尴尬.70cfea1c.png b/frontend/dist/assets/011_尴尬.70cfea1c.png new file mode 100644 index 0000000..a01e450 Binary files /dev/null and b/frontend/dist/assets/011_尴尬.70cfea1c.png differ diff --git a/frontend/dist/assets/012_发怒.b88ce021.png b/frontend/dist/assets/012_发怒.b88ce021.png new file mode 100644 index 0000000..c7a208e Binary files /dev/null and b/frontend/dist/assets/012_发怒.b88ce021.png differ diff --git a/frontend/dist/assets/013_调皮.f3363541.png b/frontend/dist/assets/013_调皮.f3363541.png new file mode 100644 index 0000000..72e3f1c Binary files /dev/null and b/frontend/dist/assets/013_调皮.f3363541.png differ diff --git a/frontend/dist/assets/014_呲牙.3cd1fb7c.png b/frontend/dist/assets/014_呲牙.3cd1fb7c.png new file mode 100644 index 0000000..d615596 Binary files /dev/null and b/frontend/dist/assets/014_呲牙.3cd1fb7c.png differ diff --git a/frontend/dist/assets/015_惊讶.c9eb5e15.png b/frontend/dist/assets/015_惊讶.c9eb5e15.png new file mode 100644 index 0000000..adc6d1d Binary files /dev/null and b/frontend/dist/assets/015_惊讶.c9eb5e15.png differ diff --git a/frontend/dist/assets/016_难过.5d872489.png b/frontend/dist/assets/016_难过.5d872489.png new file mode 100644 index 0000000..927c134 Binary files /dev/null and b/frontend/dist/assets/016_难过.5d872489.png differ diff --git a/frontend/dist/assets/017_囧.59ee6551.png b/frontend/dist/assets/017_囧.59ee6551.png new file mode 100644 index 0000000..bb81402 Binary files /dev/null and b/frontend/dist/assets/017_囧.59ee6551.png differ diff --git a/frontend/dist/assets/018_抓狂.d1646df8.png b/frontend/dist/assets/018_抓狂.d1646df8.png new file mode 100644 index 0000000..71d8df8 Binary files /dev/null and b/frontend/dist/assets/018_抓狂.d1646df8.png differ diff --git a/frontend/dist/assets/019_吐.51bb226f.png b/frontend/dist/assets/019_吐.51bb226f.png new file mode 100644 index 0000000..7a33ba0 Binary files /dev/null and b/frontend/dist/assets/019_吐.51bb226f.png differ diff --git a/frontend/dist/assets/020_偷笑.59941b0b.png b/frontend/dist/assets/020_偷笑.59941b0b.png new file mode 100644 index 0000000..6c26f9b Binary files /dev/null and b/frontend/dist/assets/020_偷笑.59941b0b.png differ diff --git a/frontend/dist/assets/021_愉快.47582f99.png b/frontend/dist/assets/021_愉快.47582f99.png new file mode 100644 index 0000000..f65c5e8 Binary files /dev/null and b/frontend/dist/assets/021_愉快.47582f99.png differ diff --git a/frontend/dist/assets/022_白眼.ca492234.png b/frontend/dist/assets/022_白眼.ca492234.png new file mode 100644 index 0000000..f2cc5d8 Binary files /dev/null and b/frontend/dist/assets/022_白眼.ca492234.png differ diff --git a/frontend/dist/assets/023_傲慢.651b4c79.png b/frontend/dist/assets/023_傲慢.651b4c79.png new file mode 100644 index 0000000..9d56e08 Binary files /dev/null and b/frontend/dist/assets/023_傲慢.651b4c79.png differ diff --git a/frontend/dist/assets/024_困.4556c7db.png b/frontend/dist/assets/024_困.4556c7db.png new file mode 100644 index 0000000..6525e88 Binary files /dev/null and b/frontend/dist/assets/024_困.4556c7db.png differ diff --git a/frontend/dist/assets/025_惊恐.ed5cfeab.png b/frontend/dist/assets/025_惊恐.ed5cfeab.png new file mode 100644 index 0000000..59ffdc0 Binary files /dev/null and b/frontend/dist/assets/025_惊恐.ed5cfeab.png differ diff --git a/frontend/dist/assets/026_憨笑.6d317a05.png b/frontend/dist/assets/026_憨笑.6d317a05.png new file mode 100644 index 0000000..1881de3 Binary files /dev/null and b/frontend/dist/assets/026_憨笑.6d317a05.png differ diff --git a/frontend/dist/assets/027_悠闲.cef28253.png b/frontend/dist/assets/027_悠闲.cef28253.png new file mode 100644 index 0000000..1dd32cf Binary files /dev/null and b/frontend/dist/assets/027_悠闲.cef28253.png differ diff --git a/frontend/dist/assets/028_咒骂.a26d48fa.png b/frontend/dist/assets/028_咒骂.a26d48fa.png new file mode 100644 index 0000000..549de88 Binary files /dev/null and b/frontend/dist/assets/028_咒骂.a26d48fa.png differ diff --git a/frontend/dist/assets/029_疑问.aaa09269.png b/frontend/dist/assets/029_疑问.aaa09269.png new file mode 100644 index 0000000..aea4507 Binary files /dev/null and b/frontend/dist/assets/029_疑问.aaa09269.png differ diff --git a/frontend/dist/assets/030_嘘.40e8213d.png b/frontend/dist/assets/030_嘘.40e8213d.png new file mode 100644 index 0000000..18793fe Binary files /dev/null and b/frontend/dist/assets/030_嘘.40e8213d.png differ diff --git a/frontend/dist/assets/031_晕.44e3541a.png b/frontend/dist/assets/031_晕.44e3541a.png new file mode 100644 index 0000000..423ebfc Binary files /dev/null and b/frontend/dist/assets/031_晕.44e3541a.png differ diff --git a/frontend/dist/assets/032_衰.1a3910a6.png b/frontend/dist/assets/032_衰.1a3910a6.png new file mode 100644 index 0000000..49ff6a8 Binary files /dev/null and b/frontend/dist/assets/032_衰.1a3910a6.png differ diff --git a/frontend/dist/assets/033_骷髅.3c9202dc.png b/frontend/dist/assets/033_骷髅.3c9202dc.png new file mode 100644 index 0000000..7542615 Binary files /dev/null and b/frontend/dist/assets/033_骷髅.3c9202dc.png differ diff --git a/frontend/dist/assets/034_敲打.b2798ca7.png b/frontend/dist/assets/034_敲打.b2798ca7.png new file mode 100644 index 0000000..9d2fdaa Binary files /dev/null and b/frontend/dist/assets/034_敲打.b2798ca7.png differ diff --git a/frontend/dist/assets/035_再见.db23652c.png b/frontend/dist/assets/035_再见.db23652c.png new file mode 100644 index 0000000..5f45eb5 Binary files /dev/null and b/frontend/dist/assets/035_再见.db23652c.png differ diff --git a/frontend/dist/assets/036_擦汗.b46fa893.png b/frontend/dist/assets/036_擦汗.b46fa893.png new file mode 100644 index 0000000..2b12443 Binary files /dev/null and b/frontend/dist/assets/036_擦汗.b46fa893.png differ diff --git a/frontend/dist/assets/037_抠鼻.64bc8033.png b/frontend/dist/assets/037_抠鼻.64bc8033.png new file mode 100644 index 0000000..4f3ab6d Binary files /dev/null and b/frontend/dist/assets/037_抠鼻.64bc8033.png differ diff --git a/frontend/dist/assets/038_鼓掌.2a84e4c7.png b/frontend/dist/assets/038_鼓掌.2a84e4c7.png new file mode 100644 index 0000000..4039892 Binary files /dev/null and b/frontend/dist/assets/038_鼓掌.2a84e4c7.png differ diff --git a/frontend/dist/assets/039_坏笑.4998b91f.png b/frontend/dist/assets/039_坏笑.4998b91f.png new file mode 100644 index 0000000..bb0d5bf Binary files /dev/null and b/frontend/dist/assets/039_坏笑.4998b91f.png differ diff --git a/frontend/dist/assets/040_右哼哼.27d8126d.png b/frontend/dist/assets/040_右哼哼.27d8126d.png new file mode 100644 index 0000000..49fa38c Binary files /dev/null and b/frontend/dist/assets/040_右哼哼.27d8126d.png differ diff --git a/frontend/dist/assets/041_鄙视.7e22890d.png b/frontend/dist/assets/041_鄙视.7e22890d.png new file mode 100644 index 0000000..bf22463 Binary files /dev/null and b/frontend/dist/assets/041_鄙视.7e22890d.png differ diff --git a/frontend/dist/assets/042_委屈.a5caf83a.png b/frontend/dist/assets/042_委屈.a5caf83a.png new file mode 100644 index 0000000..f04d409 Binary files /dev/null and b/frontend/dist/assets/042_委屈.a5caf83a.png differ diff --git a/frontend/dist/assets/043_快哭了.62b1b67c.png b/frontend/dist/assets/043_快哭了.62b1b67c.png new file mode 100644 index 0000000..ce59b72 Binary files /dev/null and b/frontend/dist/assets/043_快哭了.62b1b67c.png differ diff --git a/frontend/dist/assets/044_阴险.3697222b.png b/frontend/dist/assets/044_阴险.3697222b.png new file mode 100644 index 0000000..f49563a Binary files /dev/null and b/frontend/dist/assets/044_阴险.3697222b.png differ diff --git a/frontend/dist/assets/045_亲亲.dfa6bbdf.png b/frontend/dist/assets/045_亲亲.dfa6bbdf.png new file mode 100644 index 0000000..2896ca1 Binary files /dev/null and b/frontend/dist/assets/045_亲亲.dfa6bbdf.png differ diff --git a/frontend/dist/assets/046_可怜.634845ad.png b/frontend/dist/assets/046_可怜.634845ad.png new file mode 100644 index 0000000..742ac56 Binary files /dev/null and b/frontend/dist/assets/046_可怜.634845ad.png differ diff --git a/frontend/dist/assets/047_笑脸.ab25a28c.png b/frontend/dist/assets/047_笑脸.ab25a28c.png new file mode 100644 index 0000000..0c2200d Binary files /dev/null and b/frontend/dist/assets/047_笑脸.ab25a28c.png differ diff --git a/frontend/dist/assets/048_生病.cd7aadb3.png b/frontend/dist/assets/048_生病.cd7aadb3.png new file mode 100644 index 0000000..6bca2f0 Binary files /dev/null and b/frontend/dist/assets/048_生病.cd7aadb3.png differ diff --git a/frontend/dist/assets/049_脸红.9ecb5c1c.png b/frontend/dist/assets/049_脸红.9ecb5c1c.png new file mode 100644 index 0000000..164ae21 Binary files /dev/null and b/frontend/dist/assets/049_脸红.9ecb5c1c.png differ diff --git a/frontend/dist/assets/050_破涕为笑.a3d2342d.png b/frontend/dist/assets/050_破涕为笑.a3d2342d.png new file mode 100644 index 0000000..69b9a49 Binary files /dev/null and b/frontend/dist/assets/050_破涕为笑.a3d2342d.png differ diff --git a/frontend/dist/assets/051_恐惧.7af18313.png b/frontend/dist/assets/051_恐惧.7af18313.png new file mode 100644 index 0000000..976b705 Binary files /dev/null and b/frontend/dist/assets/051_恐惧.7af18313.png differ diff --git a/frontend/dist/assets/052_失望.87e0479b.png b/frontend/dist/assets/052_失望.87e0479b.png new file mode 100644 index 0000000..28f031e Binary files /dev/null and b/frontend/dist/assets/052_失望.87e0479b.png differ diff --git a/frontend/dist/assets/053_无语.6220ee7c.png b/frontend/dist/assets/053_无语.6220ee7c.png new file mode 100644 index 0000000..9bf0b26 Binary files /dev/null and b/frontend/dist/assets/053_无语.6220ee7c.png differ diff --git a/frontend/dist/assets/054_嘿哈.2116e692.png b/frontend/dist/assets/054_嘿哈.2116e692.png new file mode 100644 index 0000000..912dbe1 Binary files /dev/null and b/frontend/dist/assets/054_嘿哈.2116e692.png differ diff --git a/frontend/dist/assets/055_捂脸.28f3a0d3.png b/frontend/dist/assets/055_捂脸.28f3a0d3.png new file mode 100644 index 0000000..c20cab8 Binary files /dev/null and b/frontend/dist/assets/055_捂脸.28f3a0d3.png differ diff --git a/frontend/dist/assets/056_奸笑.9cf99423.png b/frontend/dist/assets/056_奸笑.9cf99423.png new file mode 100644 index 0000000..914890b Binary files /dev/null and b/frontend/dist/assets/056_奸笑.9cf99423.png differ diff --git a/frontend/dist/assets/057_机智.93c3d05a.png b/frontend/dist/assets/057_机智.93c3d05a.png new file mode 100644 index 0000000..e802d4d Binary files /dev/null and b/frontend/dist/assets/057_机智.93c3d05a.png differ diff --git a/frontend/dist/assets/058_皱眉.efe09ed7.png b/frontend/dist/assets/058_皱眉.efe09ed7.png new file mode 100644 index 0000000..e4e0ee1 Binary files /dev/null and b/frontend/dist/assets/058_皱眉.efe09ed7.png differ diff --git a/frontend/dist/assets/059_耶.a6bc3d2b.png b/frontend/dist/assets/059_耶.a6bc3d2b.png new file mode 100644 index 0000000..ccb1b82 Binary files /dev/null and b/frontend/dist/assets/059_耶.a6bc3d2b.png differ diff --git a/frontend/dist/assets/060_吃瓜.a2a158de.png b/frontend/dist/assets/060_吃瓜.a2a158de.png new file mode 100644 index 0000000..bd99b78 Binary files /dev/null and b/frontend/dist/assets/060_吃瓜.a2a158de.png differ diff --git a/frontend/dist/assets/061_加油.77c81f5b.png b/frontend/dist/assets/061_加油.77c81f5b.png new file mode 100644 index 0000000..4141148 Binary files /dev/null and b/frontend/dist/assets/061_加油.77c81f5b.png differ diff --git a/frontend/dist/assets/062_汗.be95535c.png b/frontend/dist/assets/062_汗.be95535c.png new file mode 100644 index 0000000..aa8e7e3 Binary files /dev/null and b/frontend/dist/assets/062_汗.be95535c.png differ diff --git a/frontend/dist/assets/063_天啊.a8355bf9.png b/frontend/dist/assets/063_天啊.a8355bf9.png new file mode 100644 index 0000000..95aefcd Binary files /dev/null and b/frontend/dist/assets/063_天啊.a8355bf9.png differ diff --git a/frontend/dist/assets/064_Emm.787be530.png b/frontend/dist/assets/064_Emm.787be530.png new file mode 100644 index 0000000..94f777d Binary files /dev/null and b/frontend/dist/assets/064_Emm.787be530.png differ diff --git a/frontend/dist/assets/065_社会社会.a5f5902a.png b/frontend/dist/assets/065_社会社会.a5f5902a.png new file mode 100644 index 0000000..0770fa5 Binary files /dev/null and b/frontend/dist/assets/065_社会社会.a5f5902a.png differ diff --git a/frontend/dist/assets/066_旺柴.7825a175.png b/frontend/dist/assets/066_旺柴.7825a175.png new file mode 100644 index 0000000..796419e Binary files /dev/null and b/frontend/dist/assets/066_旺柴.7825a175.png differ diff --git a/frontend/dist/assets/067_好的.a9fffc64.png b/frontend/dist/assets/067_好的.a9fffc64.png new file mode 100644 index 0000000..989ac10 Binary files /dev/null and b/frontend/dist/assets/067_好的.a9fffc64.png differ diff --git a/frontend/dist/assets/068_打脸.560c8d1f.png b/frontend/dist/assets/068_打脸.560c8d1f.png new file mode 100644 index 0000000..e2cf5e5 Binary files /dev/null and b/frontend/dist/assets/068_打脸.560c8d1f.png differ diff --git a/frontend/dist/assets/069_哇.74cdcc27.png b/frontend/dist/assets/069_哇.74cdcc27.png new file mode 100644 index 0000000..8b35491 Binary files /dev/null and b/frontend/dist/assets/069_哇.74cdcc27.png differ diff --git a/frontend/dist/assets/070_翻白眼.ecb744e2.png b/frontend/dist/assets/070_翻白眼.ecb744e2.png new file mode 100644 index 0000000..81ad985 Binary files /dev/null and b/frontend/dist/assets/070_翻白眼.ecb744e2.png differ diff --git a/frontend/dist/assets/071_666.281fb9b6.png b/frontend/dist/assets/071_666.281fb9b6.png new file mode 100644 index 0000000..ff6aa92 Binary files /dev/null and b/frontend/dist/assets/071_666.281fb9b6.png differ diff --git a/frontend/dist/assets/072_让我看看.cee96a9f.png b/frontend/dist/assets/072_让我看看.cee96a9f.png new file mode 100644 index 0000000..0ccee49 Binary files /dev/null and b/frontend/dist/assets/072_让我看看.cee96a9f.png differ diff --git a/frontend/dist/assets/073_叹气.712846f3.png b/frontend/dist/assets/073_叹气.712846f3.png new file mode 100644 index 0000000..63c6a02 Binary files /dev/null and b/frontend/dist/assets/073_叹气.712846f3.png differ diff --git a/frontend/dist/assets/074_苦涩.4edf4f58.png b/frontend/dist/assets/074_苦涩.4edf4f58.png new file mode 100644 index 0000000..7b2314d Binary files /dev/null and b/frontend/dist/assets/074_苦涩.4edf4f58.png differ diff --git a/frontend/dist/assets/075_裂开.3fb97804.png b/frontend/dist/assets/075_裂开.3fb97804.png new file mode 100644 index 0000000..16d0001 Binary files /dev/null and b/frontend/dist/assets/075_裂开.3fb97804.png differ diff --git a/frontend/dist/assets/076_嘴唇.59b9c0be.png b/frontend/dist/assets/076_嘴唇.59b9c0be.png new file mode 100644 index 0000000..77c8dff Binary files /dev/null and b/frontend/dist/assets/076_嘴唇.59b9c0be.png differ diff --git a/frontend/dist/assets/077_爱心.a09c823b.png b/frontend/dist/assets/077_爱心.a09c823b.png new file mode 100644 index 0000000..6a9403d Binary files /dev/null and b/frontend/dist/assets/077_爱心.a09c823b.png differ diff --git a/frontend/dist/assets/078_心碎.9a4fb37d.png b/frontend/dist/assets/078_心碎.9a4fb37d.png new file mode 100644 index 0000000..629224a Binary files /dev/null and b/frontend/dist/assets/078_心碎.9a4fb37d.png differ diff --git a/frontend/dist/assets/079_拥抱.e529a46b.png b/frontend/dist/assets/079_拥抱.e529a46b.png new file mode 100644 index 0000000..9cd2f50 Binary files /dev/null and b/frontend/dist/assets/079_拥抱.e529a46b.png differ diff --git a/frontend/dist/assets/080_强.64fe98a8.png b/frontend/dist/assets/080_强.64fe98a8.png new file mode 100644 index 0000000..3e88fa8 Binary files /dev/null and b/frontend/dist/assets/080_强.64fe98a8.png differ diff --git a/frontend/dist/assets/081_弱.07ddf3a5.png b/frontend/dist/assets/081_弱.07ddf3a5.png new file mode 100644 index 0000000..306505c Binary files /dev/null and b/frontend/dist/assets/081_弱.07ddf3a5.png differ diff --git a/frontend/dist/assets/082_握手.aeb86265.png b/frontend/dist/assets/082_握手.aeb86265.png new file mode 100644 index 0000000..b625691 Binary files /dev/null and b/frontend/dist/assets/082_握手.aeb86265.png differ diff --git a/frontend/dist/assets/083_胜利.e9ff0663.png b/frontend/dist/assets/083_胜利.e9ff0663.png new file mode 100644 index 0000000..8662127 Binary files /dev/null and b/frontend/dist/assets/083_胜利.e9ff0663.png differ diff --git a/frontend/dist/assets/084_抱拳.0ae5f316.png b/frontend/dist/assets/084_抱拳.0ae5f316.png new file mode 100644 index 0000000..eb943e6 Binary files /dev/null and b/frontend/dist/assets/084_抱拳.0ae5f316.png differ diff --git a/frontend/dist/assets/085_勾引.a4c3a7b4.png b/frontend/dist/assets/085_勾引.a4c3a7b4.png new file mode 100644 index 0000000..3e5137f Binary files /dev/null and b/frontend/dist/assets/085_勾引.a4c3a7b4.png differ diff --git a/frontend/dist/assets/086_拳头.2829fdbe.png b/frontend/dist/assets/086_拳头.2829fdbe.png new file mode 100644 index 0000000..4d40db2 Binary files /dev/null and b/frontend/dist/assets/086_拳头.2829fdbe.png differ diff --git a/frontend/dist/assets/087_OK.fc42db3d.png b/frontend/dist/assets/087_OK.fc42db3d.png new file mode 100644 index 0000000..2a6e18e Binary files /dev/null and b/frontend/dist/assets/087_OK.fc42db3d.png differ diff --git a/frontend/dist/assets/088_合十.58cd6a1d.png b/frontend/dist/assets/088_合十.58cd6a1d.png new file mode 100644 index 0000000..f92a569 Binary files /dev/null and b/frontend/dist/assets/088_合十.58cd6a1d.png differ diff --git a/frontend/dist/assets/089_啤酒.2d022508.png b/frontend/dist/assets/089_啤酒.2d022508.png new file mode 100644 index 0000000..3d28da1 Binary files /dev/null and b/frontend/dist/assets/089_啤酒.2d022508.png differ diff --git a/frontend/dist/assets/090_咖啡.8f40dc95.png b/frontend/dist/assets/090_咖啡.8f40dc95.png new file mode 100644 index 0000000..27f3ee8 Binary files /dev/null and b/frontend/dist/assets/090_咖啡.8f40dc95.png differ diff --git a/frontend/dist/assets/091_蛋糕.f01a91ed.png b/frontend/dist/assets/091_蛋糕.f01a91ed.png new file mode 100644 index 0000000..4ecd31b Binary files /dev/null and b/frontend/dist/assets/091_蛋糕.f01a91ed.png differ diff --git a/frontend/dist/assets/093_凋谢.aa715ee6.png b/frontend/dist/assets/093_凋谢.aa715ee6.png new file mode 100644 index 0000000..6b618a3 Binary files /dev/null and b/frontend/dist/assets/093_凋谢.aa715ee6.png differ diff --git a/frontend/dist/assets/095_炸弹.3dffd8e8.png b/frontend/dist/assets/095_炸弹.3dffd8e8.png new file mode 100644 index 0000000..cda16f8 Binary files /dev/null and b/frontend/dist/assets/095_炸弹.3dffd8e8.png differ diff --git a/frontend/dist/assets/096_便便.b0d5c50c.png b/frontend/dist/assets/096_便便.b0d5c50c.png new file mode 100644 index 0000000..07126f8 Binary files /dev/null and b/frontend/dist/assets/096_便便.b0d5c50c.png differ diff --git a/frontend/dist/assets/097_月亮.47389834.png b/frontend/dist/assets/097_月亮.47389834.png new file mode 100644 index 0000000..d1197e7 Binary files /dev/null and b/frontend/dist/assets/097_月亮.47389834.png differ diff --git a/frontend/dist/assets/098_太阳.89c3d0ab.png b/frontend/dist/assets/098_太阳.89c3d0ab.png new file mode 100644 index 0000000..3f9226f Binary files /dev/null and b/frontend/dist/assets/098_太阳.89c3d0ab.png differ diff --git a/frontend/dist/assets/099_庆祝.2d9e8f8a.png b/frontend/dist/assets/099_庆祝.2d9e8f8a.png new file mode 100644 index 0000000..cfdf014 Binary files /dev/null and b/frontend/dist/assets/099_庆祝.2d9e8f8a.png differ diff --git a/frontend/dist/assets/100_礼物.37ae5ec0.png b/frontend/dist/assets/100_礼物.37ae5ec0.png new file mode 100644 index 0000000..2eb828c Binary files /dev/null and b/frontend/dist/assets/100_礼物.37ae5ec0.png differ diff --git a/frontend/dist/assets/102_發.f43fee5c.png b/frontend/dist/assets/102_發.f43fee5c.png new file mode 100644 index 0000000..56c8806 Binary files /dev/null and b/frontend/dist/assets/102_發.f43fee5c.png differ diff --git a/frontend/dist/assets/103_福.58c94555.png b/frontend/dist/assets/103_福.58c94555.png new file mode 100644 index 0000000..9c9158b Binary files /dev/null and b/frontend/dist/assets/103_福.58c94555.png differ diff --git a/frontend/dist/assets/104_烟花.61568e1e.png b/frontend/dist/assets/104_烟花.61568e1e.png new file mode 100644 index 0000000..330aca8 Binary files /dev/null and b/frontend/dist/assets/104_烟花.61568e1e.png differ diff --git a/frontend/dist/assets/105_爆竹.35531687.png b/frontend/dist/assets/105_爆竹.35531687.png new file mode 100644 index 0000000..f1a6a0b Binary files /dev/null and b/frontend/dist/assets/105_爆竹.35531687.png differ diff --git a/frontend/dist/assets/106_猪头.7eb8ff1d.png b/frontend/dist/assets/106_猪头.7eb8ff1d.png new file mode 100644 index 0000000..f44055c Binary files /dev/null and b/frontend/dist/assets/106_猪头.7eb8ff1d.png differ diff --git a/frontend/dist/assets/107_跳跳.24101efa.png b/frontend/dist/assets/107_跳跳.24101efa.png new file mode 100644 index 0000000..e211b8c Binary files /dev/null and b/frontend/dist/assets/107_跳跳.24101efa.png differ diff --git a/frontend/dist/assets/108_发抖.3eabd306.png b/frontend/dist/assets/108_发抖.3eabd306.png new file mode 100644 index 0000000..41596e8 Binary files /dev/null and b/frontend/dist/assets/108_发抖.3eabd306.png differ diff --git a/frontend/dist/assets/109_转圈.67669ca4.png b/frontend/dist/assets/109_转圈.67669ca4.png new file mode 100644 index 0000000..f81e84f Binary files /dev/null and b/frontend/dist/assets/109_转圈.67669ca4.png differ diff --git a/frontend/dist/assets/emoji.b5d5ea11.png b/frontend/dist/assets/emoji.b5d5ea11.png new file mode 100644 index 0000000..840cda1 Binary files /dev/null and b/frontend/dist/assets/emoji.b5d5ea11.png differ diff --git a/frontend/dist/assets/index.beba636e.js b/frontend/dist/assets/index.beba636e.js new file mode 100644 index 0000000..009d820 --- /dev/null +++ b/frontend/dist/assets/index.beba636e.js @@ -0,0 +1,348 @@ +function E1(e,t){for(var n=0;nr[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const a of i.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&r(a)}).observe(document,{childList:!0,subtree:!0});function n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerpolicy&&(i.referrerPolicy=o.referrerpolicy),o.crossorigin==="use-credentials"?i.credentials="include":o.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();var Hr=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ud(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function aE(e){var t=e.default;if(typeof t=="function"){var n=function(){return t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(n,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}),n}var f={exports:{}},gt={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var _s=Symbol.for("react.element"),lE=Symbol.for("react.portal"),sE=Symbol.for("react.fragment"),cE=Symbol.for("react.strict_mode"),uE=Symbol.for("react.profiler"),dE=Symbol.for("react.provider"),fE=Symbol.for("react.context"),vE=Symbol.for("react.forward_ref"),pE=Symbol.for("react.suspense"),gE=Symbol.for("react.memo"),hE=Symbol.for("react.lazy"),Bm=Symbol.iterator;function mE(e){return e===null||typeof e!="object"?null:(e=Bm&&e[Bm]||e["@@iterator"],typeof e=="function"?e:null)}var M1={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},O1=Object.assign,R1={};function Qa(e,t,n){this.props=e,this.context=t,this.refs=R1,this.updater=n||M1}Qa.prototype.isReactComponent={};Qa.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Qa.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function I1(){}I1.prototype=Qa.prototype;function Ag(e,t,n){this.props=e,this.context=t,this.refs=R1,this.updater=n||M1}var Dg=Ag.prototype=new I1;Dg.constructor=Ag;O1(Dg,Qa.prototype);Dg.isPureReactComponent=!0;var jm=Array.isArray,P1=Object.prototype.hasOwnProperty,Lg={current:null},T1={key:!0,ref:!0,__self:!0,__source:!0};function N1(e,t,n){var r,o={},i=null,a=null;if(t!=null)for(r in t.ref!==void 0&&(a=t.ref),t.key!==void 0&&(i=""+t.key),t)P1.call(t,r)&&!T1.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(l===1)o.children=n;else if(1>>1,k=M[B];if(0>>1;Bo(W,A))Yo(K,W)?(M[B]=K,M[Y]=A,B=Y):(M[B]=W,M[H]=A,B=H);else if(Yo(K,A))M[B]=K,M[Y]=A,B=Y;else break e}}return L}function o(M,L){var A=M.sortIndex-L.sortIndex;return A!==0?A:M.id-L.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var a=Date,l=a.now();e.unstable_now=function(){return a.now()-l}}var s=[],c=[],u=1,d=null,v=3,h=!1,g=!1,p=!1,b=typeof setTimeout=="function"?setTimeout:null,m=typeof clearTimeout=="function"?clearTimeout:null,y=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function S(M){for(var L=n(c);L!==null;){if(L.callback===null)r(c);else if(L.startTime<=M)r(c),L.sortIndex=L.expirationTime,t(s,L);else break;L=n(c)}}function x(M){if(p=!1,S(M),!g)if(n(s)!==null)g=!0,_($);else{var L=n(c);L!==null&&O(x,L.startTime-M)}}function $(M,L){g=!1,p&&(p=!1,m(R),R=-1),h=!0;var A=v;try{for(S(L),d=n(s);d!==null&&(!(d.expirationTime>L)||M&&!I());){var B=d.callback;if(typeof B=="function"){d.callback=null,v=d.priorityLevel;var k=B(d.expirationTime<=L);L=e.unstable_now(),typeof k=="function"?d.callback=k:d===n(s)&&r(s),S(L)}else r(s);d=n(s)}if(d!==null)var j=!0;else{var H=n(c);H!==null&&O(x,H.startTime-L),j=!1}return j}finally{d=null,v=A,h=!1}}var E=!1,w=null,R=-1,P=5,N=-1;function I(){return!(e.unstable_now()-NM||125B?(M.sortIndex=A,t(c,M),n(s)===null&&M===n(c)&&(p?(m(R),R=-1):p=!0,O(x,A-B))):(M.sortIndex=k,t(s,M),g||h||(g=!0,_($))),M},e.unstable_shouldYield=I,e.unstable_wrapCallback=function(M){var L=v;return function(){var A=v;v=L;try{return M.apply(this,arguments)}finally{v=A}}}})(A1);(function(e){e.exports=A1})(_1);/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var D1=f.exports,or=_1.exports;function me(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Nv=Object.prototype.hasOwnProperty,xE=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Wm={},Vm={};function wE(e){return Nv.call(Vm,e)?!0:Nv.call(Wm,e)?!1:xE.test(e)?Vm[e]=!0:(Wm[e]=!0,!1)}function $E(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function EE(e,t,n,r){if(t===null||typeof t>"u"||$E(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ln(e,t,n,r,o,i,a){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=a}var Sn={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Sn[e]=new Ln(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Sn[t]=new Ln(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Sn[e]=new Ln(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Sn[e]=new Ln(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Sn[e]=new Ln(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Sn[e]=new Ln(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Sn[e]=new Ln(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Sn[e]=new Ln(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Sn[e]=new Ln(e,5,!1,e.toLowerCase(),null,!1,!1)});var Fg=/[\-:]([a-z])/g;function kg(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Fg,kg);Sn[t]=new Ln(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Fg,kg);Sn[t]=new Ln(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Fg,kg);Sn[t]=new Ln(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Sn[e]=new Ln(e,1,!1,e.toLowerCase(),null,!1,!1)});Sn.xlinkHref=new Ln("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Sn[e]=new Ln(e,1,!1,e.toLowerCase(),null,!0,!0)});function Bg(e,t,n,r){var o=Sn.hasOwnProperty(t)?Sn[t]:null;(o!==null?o.type!==0:r||!(2l||o[a]!==i[l]){var s=` +`+o[a].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=a&&0<=l);break}}}finally{Ef=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Rl(e):""}function ME(e){switch(e.tag){case 5:return Rl(e.type);case 16:return Rl("Lazy");case 13:return Rl("Suspense");case 19:return Rl("SuspenseList");case 0:case 2:case 15:return e=Mf(e.type,!1),e;case 11:return e=Mf(e.type.render,!1),e;case 1:return e=Mf(e.type,!0),e;default:return""}}function Lv(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case ca:return"Fragment";case sa:return"Portal";case _v:return"Profiler";case jg:return"StrictMode";case Av:return"Suspense";case Dv:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case F1:return(e.displayName||"Context")+".Consumer";case z1:return(e._context.displayName||"Context")+".Provider";case Hg:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Wg:return t=e.displayName||null,t!==null?t:Lv(e.type)||"Memo";case Ro:t=e._payload,e=e._init;try{return Lv(e(t))}catch{}}return null}function OE(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Lv(t);case 8:return t===jg?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ko(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function B1(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function RE(e){var t=B1(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(a){r=""+a,i.call(this,a)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(a){r=""+a},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ac(e){e._valueTracker||(e._valueTracker=RE(e))}function j1(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=B1(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function vu(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function zv(e,t){var n=t.checked;return Wt({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n!=null?n:e._wrapperState.initialChecked})}function Ym(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Ko(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function H1(e,t){t=t.checked,t!=null&&Bg(e,"checked",t,!1)}function Fv(e,t){H1(e,t);var n=Ko(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?kv(e,t.type,n):t.hasOwnProperty("defaultValue")&&kv(e,t.type,Ko(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Gm(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function kv(e,t,n){(t!=="number"||vu(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Il=Array.isArray;function Ma(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=lc.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function ns(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Ll={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},IE=["Webkit","ms","Moz","O"];Object.keys(Ll).forEach(function(e){IE.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Ll[t]=Ll[e]})});function Y1(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Ll.hasOwnProperty(e)&&Ll[e]?(""+t).trim():t+"px"}function G1(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=Y1(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var PE=Wt({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Hv(e,t){if(t){if(PE[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(me(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(me(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(me(61))}if(t.style!=null&&typeof t.style!="object")throw Error(me(62))}}function Wv(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Vv=null;function Vg(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Uv=null,Oa=null,Ra=null;function Xm(e){if(e=zs(e)){if(typeof Uv!="function")throw Error(me(280));var t=e.stateNode;t&&(t=gd(t),Uv(e.stateNode,e.type,t))}}function K1(e){Oa?Ra?Ra.push(e):Ra=[e]:Oa=e}function q1(){if(Oa){var e=Oa,t=Ra;if(Ra=Oa=null,Xm(e),t)for(e=0;e>>=0,e===0?32:31-(jE(e)/HE|0)|0}var sc=64,cc=4194304;function Pl(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function mu(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,a=n&268435455;if(a!==0){var l=a&~o;l!==0?r=Pl(l):(i&=a,i!==0&&(r=Pl(i)))}else a=n&~o,a!==0?r=Pl(a):i!==0&&(r=Pl(i));if(r===0)return 0;if(t!==0&&t!==r&&(t&o)===0&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if((r&4)!==0&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Ds(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ar(t),e[t]=n}function YE(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Fl),i0=String.fromCharCode(32),a0=!1;function gS(e,t){switch(e){case"keyup":return SM.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function hS(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ua=!1;function xM(e,t){switch(e){case"compositionend":return hS(t);case"keypress":return t.which!==32?null:(a0=!0,i0);case"textInput":return e=t.data,e===i0&&a0?null:e;default:return null}}function wM(e,t){if(ua)return e==="compositionend"||!Zg&&gS(e,t)?(e=vS(),Vc=qg=No=null,ua=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=u0(n)}}function SS(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?SS(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function CS(){for(var e=window,t=vu();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=vu(e.document)}return t}function Jg(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function NM(e){var t=CS(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&SS(n.ownerDocument.documentElement,n)){if(r!==null&&Jg(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=d0(n,i);var a=d0(n,r);o&&a&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==a.node||e.focusOffset!==a.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(a.node,a.offset)):(t.setEnd(a.node,a.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,da=null,Qv=null,Bl=null,Zv=!1;function f0(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Zv||da==null||da!==vu(r)||(r=da,"selectionStart"in r&&Jg(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Bl&&ss(Bl,r)||(Bl=r,r=Su(Qv,"onSelect"),0pa||(e.current=op[pa],op[pa]=null,pa--)}function _t(e,t){pa++,op[pa]=e.current,e.current=t}var qo={},On=oi(qo),Vn=oi(!1),Ri=qo;function Fa(e,t){var n=e.type.contextTypes;if(!n)return qo;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Un(e){return e=e.childContextTypes,e!=null}function xu(){zt(Vn),zt(On)}function b0(e,t,n){if(On.current!==qo)throw Error(me(168));_t(On,t),_t(Vn,n)}function PS(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(me(108,OE(e)||"Unknown",o));return Wt({},n,r)}function wu(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||qo,Ri=On.current,_t(On,e),_t(Vn,Vn.current),!0}function S0(e,t,n){var r=e.stateNode;if(!r)throw Error(me(169));n?(e=PS(e,t,Ri),r.__reactInternalMemoizedMergedChildContext=e,zt(Vn),zt(On),_t(On,e)):zt(Vn),_t(Vn,n)}var lo=null,hd=!1,Bf=!1;function TS(e){lo===null?lo=[e]:lo.push(e)}function VM(e){hd=!0,TS(e)}function ii(){if(!Bf&&lo!==null){Bf=!0;var e=0,t=Ot;try{var n=lo;for(Ot=1;e>=a,o-=a,uo=1<<32-Ar(t)+o|n<R?(P=w,w=null):P=w.sibling;var N=v(m,w,S[R],x);if(N===null){w===null&&(w=P);break}e&&w&&N.alternate===null&&t(m,w),y=i(N,y,R),E===null?$=N:E.sibling=N,E=N,w=P}if(R===S.length)return n(m,w),Ft&&ui(m,R),$;if(w===null){for(;RR?(P=w,w=null):P=w.sibling;var I=v(m,w,N.value,x);if(I===null){w===null&&(w=P);break}e&&w&&I.alternate===null&&t(m,w),y=i(I,y,R),E===null?$=I:E.sibling=I,E=I,w=P}if(N.done)return n(m,w),Ft&&ui(m,R),$;if(w===null){for(;!N.done;R++,N=S.next())N=d(m,N.value,x),N!==null&&(y=i(N,y,R),E===null?$=N:E.sibling=N,E=N);return Ft&&ui(m,R),$}for(w=r(m,w);!N.done;R++,N=S.next())N=h(w,m,R,N.value,x),N!==null&&(e&&N.alternate!==null&&w.delete(N.key===null?R:N.key),y=i(N,y,R),E===null?$=N:E.sibling=N,E=N);return e&&w.forEach(function(z){return t(m,z)}),Ft&&ui(m,R),$}function b(m,y,S,x){if(typeof S=="object"&&S!==null&&S.type===ca&&S.key===null&&(S=S.props.children),typeof S=="object"&&S!==null){switch(S.$$typeof){case ic:e:{for(var $=S.key,E=y;E!==null;){if(E.key===$){if($=S.type,$===ca){if(E.tag===7){n(m,E.sibling),y=o(E,S.props.children),y.return=m,m=y;break e}}else if(E.elementType===$||typeof $=="object"&&$!==null&&$.$$typeof===Ro&&O0($)===E.type){n(m,E.sibling),y=o(E,S.props),y.ref=hl(m,E,S),y.return=m,m=y;break e}n(m,E);break}else t(m,E);E=E.sibling}S.type===ca?(y=$i(S.props.children,m.mode,x,S.key),y.return=m,m=y):(x=Zc(S.type,S.key,S.props,null,m.mode,x),x.ref=hl(m,y,S),x.return=m,m=x)}return a(m);case sa:e:{for(E=S.key;y!==null;){if(y.key===E)if(y.tag===4&&y.stateNode.containerInfo===S.containerInfo&&y.stateNode.implementation===S.implementation){n(m,y.sibling),y=o(y,S.children||[]),y.return=m,m=y;break e}else{n(m,y);break}else t(m,y);y=y.sibling}y=Kf(S,m.mode,x),y.return=m,m=y}return a(m);case Ro:return E=S._init,b(m,y,E(S._payload),x)}if(Il(S))return g(m,y,S,x);if(dl(S))return p(m,y,S,x);hc(m,S)}return typeof S=="string"&&S!==""||typeof S=="number"?(S=""+S,y!==null&&y.tag===6?(n(m,y.sibling),y=o(y,S),y.return=m,m=y):(n(m,y),y=Gf(S,m.mode,x),y.return=m,m=y),a(m)):n(m,y)}return b}var Ba=kS(!0),BS=kS(!1),Fs={},Qr=oi(Fs),fs=oi(Fs),vs=oi(Fs);function yi(e){if(e===Fs)throw Error(me(174));return e}function sh(e,t){switch(_t(vs,t),_t(fs,e),_t(Qr,Fs),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:jv(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=jv(t,e)}zt(Qr),_t(Qr,t)}function ja(){zt(Qr),zt(fs),zt(vs)}function jS(e){yi(vs.current);var t=yi(Qr.current),n=jv(t,e.type);t!==n&&(_t(fs,e),_t(Qr,n))}function ch(e){fs.current===e&&(zt(Qr),zt(fs))}var jt=oi(0);function Iu(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||n.data==="$?"||n.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var jf=[];function uh(){for(var e=0;en?n:4,e(!0);var r=Hf.transition;Hf.transition={};try{e(!1),t()}finally{Ot=n,Hf.transition=r}}function rC(){return br().memoizedState}function KM(e,t,n){var r=Vo(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},oC(e))iC(t,n);else if(n=DS(e,t,n,r),n!==null){var o=_n();Dr(n,e,r,o),aC(n,t,r)}}function qM(e,t,n){var r=Vo(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(oC(e))iC(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var a=t.lastRenderedState,l=i(a,n);if(o.hasEagerState=!0,o.eagerState=l,Br(l,a)){var s=t.interleaved;s===null?(o.next=o,ah(t)):(o.next=s.next,s.next=o),t.interleaved=o;return}}catch{}finally{}n=DS(e,t,o,r),n!==null&&(o=_n(),Dr(n,e,r,o),aC(n,t,r))}}function oC(e){var t=e.alternate;return e===Ht||t!==null&&t===Ht}function iC(e,t){jl=Pu=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function aC(e,t,n){if((n&4194240)!==0){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Yg(e,n)}}var Tu={readContext:yr,useCallback:Cn,useContext:Cn,useEffect:Cn,useImperativeHandle:Cn,useInsertionEffect:Cn,useLayoutEffect:Cn,useMemo:Cn,useReducer:Cn,useRef:Cn,useState:Cn,useDebugValue:Cn,useDeferredValue:Cn,useTransition:Cn,useMutableSource:Cn,useSyncExternalStore:Cn,useId:Cn,unstable_isNewReconciler:!1},XM={readContext:yr,useCallback:function(e,t){return Gr().memoizedState=[e,t===void 0?null:t],e},useContext:yr,useEffect:I0,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Kc(4194308,4,ZS.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Kc(4194308,4,e,t)},useInsertionEffect:function(e,t){return Kc(4,2,e,t)},useMemo:function(e,t){var n=Gr();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Gr();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=KM.bind(null,Ht,e),[r.memoizedState,e]},useRef:function(e){var t=Gr();return e={current:e},t.memoizedState=e},useState:R0,useDebugValue:gh,useDeferredValue:function(e){return Gr().memoizedState=e},useTransition:function(){var e=R0(!1),t=e[0];return e=GM.bind(null,e[1]),Gr().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Ht,o=Gr();if(Ft){if(n===void 0)throw Error(me(407));n=n()}else{if(n=t(),fn===null)throw Error(me(349));(Pi&30)!==0||VS(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,I0(YS.bind(null,r,i,e),[e]),r.flags|=2048,hs(9,US.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=Gr(),t=fn.identifierPrefix;if(Ft){var n=fo,r=uo;n=(r&~(1<<32-Ar(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=ps++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=a.createElement(n,{is:r.is}):(e=a.createElement(n),n==="select"&&(a=e,r.multiple?a.multiple=!0:r.size&&(a.size=r.size))):e=a.createElementNS(e,n),e[Kr]=t,e[ds]=r,gC(e,t,!1,!1),t.stateNode=e;e:{switch(a=Wv(n,r),n){case"dialog":Dt("cancel",e),Dt("close",e),o=r;break;case"iframe":case"object":case"embed":Dt("load",e),o=r;break;case"video":case"audio":for(o=0;oWa&&(t.flags|=128,r=!0,ml(i,!1),t.lanes=4194304)}else{if(!r)if(e=Iu(a),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ml(i,!0),i.tail===null&&i.tailMode==="hidden"&&!a.alternate&&!Ft)return xn(t),null}else 2*Xt()-i.renderingStartTime>Wa&&n!==1073741824&&(t.flags|=128,r=!0,ml(i,!1),t.lanes=4194304);i.isBackwards?(a.sibling=t.child,t.child=a):(n=i.last,n!==null?n.sibling=a:t.child=a,i.last=a)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=Xt(),t.sibling=null,n=jt.current,_t(jt,r?n&1|2:n&1),t):(xn(t),null);case 22:case 23:return Ch(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&(t.mode&1)!==0?(er&1073741824)!==0&&(xn(t),t.subtreeFlags&6&&(t.flags|=8192)):xn(t),null;case 24:return null;case 25:return null}throw Error(me(156,t.tag))}function oO(e,t){switch(th(t),t.tag){case 1:return Un(t.type)&&xu(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ja(),zt(Vn),zt(On),uh(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 5:return ch(t),null;case 13:if(zt(jt),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(me(340));ka()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return zt(jt),null;case 4:return ja(),null;case 10:return ih(t.type._context),null;case 22:case 23:return Ch(),null;case 24:return null;default:return null}}var yc=!1,En=!1,iO=typeof WeakSet=="function"?WeakSet:Set,De=null;function ya(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Yt(e,t,r)}else n.current=null}function hp(e,t,n){try{n()}catch(r){Yt(e,t,r)}}var F0=!1;function aO(e,t){if(Jv=yu,e=CS(),Jg(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var a=0,l=-1,s=-1,c=0,u=0,d=e,v=null;t:for(;;){for(var h;d!==n||o!==0&&d.nodeType!==3||(l=a+o),d!==i||r!==0&&d.nodeType!==3||(s=a+r),d.nodeType===3&&(a+=d.nodeValue.length),(h=d.firstChild)!==null;)v=d,d=h;for(;;){if(d===e)break t;if(v===n&&++c===o&&(l=a),v===i&&++u===r&&(s=a),(h=d.nextSibling)!==null)break;d=v,v=d.parentNode}d=h}n=l===-1||s===-1?null:{start:l,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(ep={focusedElem:e,selectionRange:n},yu=!1,De=t;De!==null;)if(t=De,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,De=e;else for(;De!==null;){t=De;try{var g=t.alternate;if((t.flags&1024)!==0)switch(t.tag){case 0:case 11:case 15:break;case 1:if(g!==null){var p=g.memoizedProps,b=g.memoizedState,m=t.stateNode,y=m.getSnapshotBeforeUpdate(t.elementType===t.type?p:Rr(t.type,p),b);m.__reactInternalSnapshotBeforeUpdate=y}break;case 3:var S=t.stateNode.containerInfo;S.nodeType===1?S.textContent="":S.nodeType===9&&S.documentElement&&S.removeChild(S.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(me(163))}}catch(x){Yt(t,t.return,x)}if(e=t.sibling,e!==null){e.return=t.return,De=e;break}De=t.return}return g=F0,F0=!1,g}function Hl(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&hp(t,n,i)}o=o.next}while(o!==r)}}function bd(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function mp(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function yC(e){var t=e.alternate;t!==null&&(e.alternate=null,yC(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Kr],delete t[ds],delete t[rp],delete t[HM],delete t[WM])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function bC(e){return e.tag===5||e.tag===3||e.tag===4}function k0(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||bC(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function yp(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Cu));else if(r!==4&&(e=e.child,e!==null))for(yp(e,t,n),e=e.sibling;e!==null;)yp(e,t,n),e=e.sibling}function bp(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(bp(e,t,n),e=e.sibling;e!==null;)bp(e,t,n),e=e.sibling}var gn=null,Pr=!1;function Eo(e,t,n){for(n=n.child;n!==null;)SC(e,t,n),n=n.sibling}function SC(e,t,n){if(Xr&&typeof Xr.onCommitFiberUnmount=="function")try{Xr.onCommitFiberUnmount(dd,n)}catch{}switch(n.tag){case 5:En||ya(n,t);case 6:var r=gn,o=Pr;gn=null,Eo(e,t,n),gn=r,Pr=o,gn!==null&&(Pr?(e=gn,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):gn.removeChild(n.stateNode));break;case 18:gn!==null&&(Pr?(e=gn,n=n.stateNode,e.nodeType===8?kf(e.parentNode,n):e.nodeType===1&&kf(e,n),as(e)):kf(gn,n.stateNode));break;case 4:r=gn,o=Pr,gn=n.stateNode.containerInfo,Pr=!0,Eo(e,t,n),gn=r,Pr=o;break;case 0:case 11:case 14:case 15:if(!En&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,a=i.destroy;i=i.tag,a!==void 0&&((i&2)!==0||(i&4)!==0)&&hp(n,t,a),o=o.next}while(o!==r)}Eo(e,t,n);break;case 1:if(!En&&(ya(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(l){Yt(n,t,l)}Eo(e,t,n);break;case 21:Eo(e,t,n);break;case 22:n.mode&1?(En=(r=En)||n.memoizedState!==null,Eo(e,t,n),En=r):Eo(e,t,n);break;default:Eo(e,t,n)}}function B0(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new iO),t.forEach(function(r){var o=gO.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function Mr(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=a),r&=~i}if(r=o,r=Xt()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*sO(r/1960))-r,10e?16:e,_o===null)var r=!1;else{if(e=_o,_o=null,Au=0,(wt&6)!==0)throw Error(me(331));var o=wt;for(wt|=4,De=e.current;De!==null;){var i=De,a=i.child;if((De.flags&16)!==0){var l=i.deletions;if(l!==null){for(var s=0;sXt()-bh?wi(e,0):yh|=n),Yn(e,t)}function RC(e,t){t===0&&((e.mode&1)===0?t=1:(t=cc,cc<<=1,(cc&130023424)===0&&(cc=4194304)));var n=_n();e=ho(e,t),e!==null&&(Ds(e,t,n),Yn(e,n))}function pO(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),RC(e,n)}function gO(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(me(314))}r!==null&&r.delete(t),RC(e,n)}var IC;IC=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Vn.current)Wn=!0;else{if((e.lanes&n)===0&&(t.flags&128)===0)return Wn=!1,nO(e,t,n);Wn=(e.flags&131072)!==0}else Wn=!1,Ft&&(t.flags&1048576)!==0&&NS(t,Eu,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;qc(e,t),e=t.pendingProps;var o=Fa(t,On.current);Pa(t,n),o=fh(null,t,r,e,o,n);var i=vh();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Un(r)?(i=!0,wu(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,lh(t),o.updater=md,t.stateNode=o,o._reactInternals=t,cp(t,r,e,n),t=fp(null,t,r,!0,i,n)):(t.tag=0,Ft&&i&&eh(t),Nn(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(qc(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=mO(r),e=Rr(r,e),o){case 0:t=dp(null,t,r,e,n);break e;case 1:t=D0(null,t,r,e,n);break e;case 11:t=_0(null,t,r,e,n);break e;case 14:t=A0(null,t,r,Rr(r.type,e),n);break e}throw Error(me(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),dp(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),D0(e,t,r,o,n);case 3:e:{if(fC(t),e===null)throw Error(me(387));r=t.pendingProps,i=t.memoizedState,o=i.element,LS(e,t),Ru(t,r,null,n);var a=t.memoizedState;if(r=a.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:a.cache,pendingSuspenseBoundaries:a.pendingSuspenseBoundaries,transitions:a.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=Ha(Error(me(423)),t),t=L0(e,t,r,n,o);break e}else if(r!==o){o=Ha(Error(me(424)),t),t=L0(e,t,r,n,o);break e}else for(tr=jo(t.stateNode.containerInfo.firstChild),rr=t,Ft=!0,_r=null,n=BS(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(ka(),r===o){t=mo(e,t,n);break e}Nn(e,t,r,n)}t=t.child}return t;case 5:return jS(t),e===null&&ap(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,a=o.children,tp(r,o)?a=null:i!==null&&tp(r,i)&&(t.flags|=32),dC(e,t),Nn(e,t,a,n),t.child;case 6:return e===null&&ap(t),null;case 13:return vC(e,t,n);case 4:return sh(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Ba(t,null,r,n):Nn(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),_0(e,t,r,o,n);case 7:return Nn(e,t,t.pendingProps,n),t.child;case 8:return Nn(e,t,t.pendingProps.children,n),t.child;case 12:return Nn(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,a=o.value,_t(Mu,r._currentValue),r._currentValue=a,i!==null)if(Br(i.value,a)){if(i.children===o.children&&!Vn.current){t=mo(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var l=i.dependencies;if(l!==null){a=i.child;for(var s=l.firstContext;s!==null;){if(s.context===r){if(i.tag===1){s=vo(-1,n&-n),s.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var u=c.pending;u===null?s.next=s:(s.next=u.next,u.next=s),c.pending=s}}i.lanes|=n,s=i.alternate,s!==null&&(s.lanes|=n),lp(i.return,n,t),l.lanes|=n;break}s=s.next}}else if(i.tag===10)a=i.type===t.type?null:i.child;else if(i.tag===18){if(a=i.return,a===null)throw Error(me(341));a.lanes|=n,l=a.alternate,l!==null&&(l.lanes|=n),lp(a,n,t),a=i.sibling}else a=i.child;if(a!==null)a.return=i;else for(a=i;a!==null;){if(a===t){a=null;break}if(i=a.sibling,i!==null){i.return=a.return,a=i;break}a=a.return}i=a}Nn(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,Pa(t,n),o=yr(o),r=r(o),t.flags|=1,Nn(e,t,r,n),t.child;case 14:return r=t.type,o=Rr(r,t.pendingProps),o=Rr(r.type,o),A0(e,t,r,o,n);case 15:return cC(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),qc(e,t),t.tag=1,Un(r)?(e=!0,wu(t)):e=!1,Pa(t,n),FS(t,r,o),cp(t,r,o,n),fp(null,t,r,!0,e,n);case 19:return pC(e,t,n);case 22:return uC(e,t,n)}throw Error(me(156,t.tag))};function PC(e,t){return nS(e,t)}function hO(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function gr(e,t,n,r){return new hO(e,t,n,r)}function wh(e){return e=e.prototype,!(!e||!e.isReactComponent)}function mO(e){if(typeof e=="function")return wh(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Hg)return 11;if(e===Wg)return 14}return 2}function Uo(e,t){var n=e.alternate;return n===null?(n=gr(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Zc(e,t,n,r,o,i){var a=2;if(r=e,typeof e=="function")wh(e)&&(a=1);else if(typeof e=="string")a=5;else e:switch(e){case ca:return $i(n.children,o,i,t);case jg:a=8,o|=8;break;case _v:return e=gr(12,n,t,o|2),e.elementType=_v,e.lanes=i,e;case Av:return e=gr(13,n,t,o),e.elementType=Av,e.lanes=i,e;case Dv:return e=gr(19,n,t,o),e.elementType=Dv,e.lanes=i,e;case k1:return Cd(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case z1:a=10;break e;case F1:a=9;break e;case Hg:a=11;break e;case Wg:a=14;break e;case Ro:a=16,r=null;break e}throw Error(me(130,e==null?e:typeof e,""))}return t=gr(a,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function $i(e,t,n,r){return e=gr(7,e,r,t),e.lanes=n,e}function Cd(e,t,n,r){return e=gr(22,e,r,t),e.elementType=k1,e.lanes=n,e.stateNode={isHidden:!1},e}function Gf(e,t,n){return e=gr(6,e,null,t),e.lanes=n,e}function Kf(e,t,n){return t=gr(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function yO(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Rf(0),this.expirationTimes=Rf(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Rf(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function $h(e,t,n,r,o,i,a,l,s){return e=new yO(e,t,n,l,s),t===1?(t=1,i===!0&&(t|=8)):t=0,i=gr(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},lh(i),e}function bO(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(n){console.error(n)}}t(),e.exports=ir})(Gn);const zu=ud(Gn.exports),$O=E1({__proto__:null,default:zu},[Gn.exports]);var AC,K0=Gn.exports;AC=K0.createRoot,K0.hydrateRoot;var $p={exports:{}},_i={},Rh={exports:{}},EO="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED",MO=EO,OO=MO;function DC(){}function LC(){}LC.resetWarningCache=DC;var RO=function(){function e(r,o,i,a,l,s){if(s!==OO){var c=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw c.name="Invariant Violation",c}}e.isRequired=e;function t(){return e}var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:LC,resetWarningCache:DC};return n.PropTypes=n,n};Rh.exports=RO();var Ep={exports:{}},Wr={},Fu={exports:{}};(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=u;/*! + * Adapted from jQuery UI core + * + * http://jqueryui.com + * + * Copyright 2014 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/category/ui-core/ + */var n="none",r="contents",o=/input|select|textarea|button|object|iframe/;function i(d,v){return v.getPropertyValue("overflow")!=="visible"||d.scrollWidth<=0&&d.scrollHeight<=0}function a(d){var v=d.offsetWidth<=0&&d.offsetHeight<=0;if(v&&!d.innerHTML)return!0;try{var h=window.getComputedStyle(d),g=h.getPropertyValue("display");return v?g!==r&&i(d,h):g===n}catch{return console.warn("Failed to inspect element style"),!1}}function l(d){for(var v=d,h=d.getRootNode&&d.getRootNode();v&&v!==document.body;){if(h&&v===h&&(v=h.host.parentNode),a(v))return!1;v=v.parentNode}return!0}function s(d,v){var h=d.nodeName.toLowerCase(),g=o.test(h)&&!d.disabled||h==="a"&&d.href||v;return g&&l(d)}function c(d){var v=d.getAttribute("tabindex");v===null&&(v=void 0);var h=isNaN(v);return(h||v>=0)&&s(d,!h)}function u(d){var v=[].slice.call(d.querySelectorAll("*"),0).reduce(function(h,g){return h.concat(g.shadowRoot?u(g.shadowRoot):[g])},[]);return v.filter(c)}e.exports=t.default})(Fu,Fu.exports);Object.defineProperty(Wr,"__esModule",{value:!0});Wr.resetState=NO;Wr.log=_O;Wr.handleBlur=ys;Wr.handleFocus=bs;Wr.markForFocusLater=AO;Wr.returnFocus=DO;Wr.popWithoutFocus=LO;Wr.setupScopedFocus=zO;Wr.teardownScopedFocus=FO;var IO=Fu.exports,PO=TO(IO);function TO(e){return e&&e.__esModule?e:{default:e}}var Va=[],Sa=null,Mp=!1;function NO(){Va=[]}function _O(){}function ys(){Mp=!0}function bs(){if(Mp){if(Mp=!1,!Sa)return;setTimeout(function(){if(!Sa.contains(document.activeElement)){var e=(0,PO.default)(Sa)[0]||Sa;e.focus()}},0)}}function AO(){Va.push(document.activeElement)}function DO(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,t=null;try{Va.length!==0&&(t=Va.pop(),t.focus({preventScroll:e}));return}catch{console.warn(["You tried to return focus to",t,"but it is not in the DOM anymore"].join(" "))}}function LO(){Va.length>0&&Va.pop()}function zO(e){Sa=e,window.addEventListener?(window.addEventListener("blur",ys,!1),document.addEventListener("focus",bs,!0)):(window.attachEvent("onBlur",ys),document.attachEvent("onFocus",bs))}function FO(){Sa=null,window.addEventListener?(window.removeEventListener("blur",ys),document.removeEventListener("focus",bs)):(window.detachEvent("onBlur",ys),document.detachEvent("onFocus",bs))}var Op={exports:{}};(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var n=Fu.exports,r=o(n);function o(l){return l&&l.__esModule?l:{default:l}}function i(){var l=arguments.length>0&&arguments[0]!==void 0?arguments[0]:document;return l.activeElement.shadowRoot?i(l.activeElement.shadowRoot):l.activeElement}function a(l,s){var c=(0,r.default)(l);if(!c.length){s.preventDefault();return}var u=void 0,d=s.shiftKey,v=c[0],h=c[c.length-1],g=i();if(l===g){if(!d)return;u=h}if(h===g&&!d&&(u=v),v===g&&d&&(u=h),u){s.preventDefault(),u.focus();return}var p=/(\bChrome\b|\bSafari\b)\//.exec(navigator.userAgent),b=p!=null&&p[1]!="Chrome"&&/\biPod\b|\biPad\b/g.exec(navigator.userAgent)==null;if(!!b){var m=c.indexOf(g);if(m>-1&&(m+=d?-1:1),u=c[m],typeof u>"u"){s.preventDefault(),u=d?h:v,u.focus();return}s.preventDefault(),u.focus()}}e.exports=t.default})(Op,Op.exports);var Vr={},kO=function(){},BO=kO,Lr={},zC={exports:{}};/*! + Copyright (c) 2015 Jed Watson. + Based on code that is Copyright 2013-2015, Facebook, Inc. + All rights reserved. +*/(function(e){(function(){var t=!!(typeof window<"u"&&window.document&&window.document.createElement),n={canUseDOM:t,canUseWorkers:typeof Worker<"u",canUseEventListeners:t&&!!(window.addEventListener||window.attachEvent),canUseViewport:t&&!!window.screen};e.exports?e.exports=n:window.ExecutionEnvironment=n})()})(zC);Object.defineProperty(Lr,"__esModule",{value:!0});Lr.canUseDOM=Lr.SafeNodeList=Lr.SafeHTMLCollection=void 0;var jO=zC.exports,HO=WO(jO);function WO(e){return e&&e.__esModule?e:{default:e}}var Md=HO.default,VO=Md.canUseDOM?window.HTMLElement:{};Lr.SafeHTMLCollection=Md.canUseDOM?window.HTMLCollection:{};Lr.SafeNodeList=Md.canUseDOM?window.NodeList:{};Lr.canUseDOM=Md.canUseDOM;Lr.default=VO;Object.defineProperty(Vr,"__esModule",{value:!0});Vr.resetState=qO;Vr.log=XO;Vr.assertNodeList=FC;Vr.setElement=QO;Vr.validateElement=Ih;Vr.hide=ZO;Vr.show=JO;Vr.documentNotReadyOrSSRTesting=eR;var UO=BO,YO=KO(UO),GO=Lr;function KO(e){return e&&e.__esModule?e:{default:e}}var fr=null;function qO(){fr&&(fr.removeAttribute?fr.removeAttribute("aria-hidden"):fr.length!=null?fr.forEach(function(e){return e.removeAttribute("aria-hidden")}):document.querySelectorAll(fr).forEach(function(e){return e.removeAttribute("aria-hidden")})),fr=null}function XO(){}function FC(e,t){if(!e||!e.length)throw new Error("react-modal: No elements were found for selector "+t+".")}function QO(e){var t=e;if(typeof t=="string"&&GO.canUseDOM){var n=document.querySelectorAll(t);FC(n,t),t=n}return fr=t||fr,fr}function Ih(e){var t=e||fr;return t?Array.isArray(t)||t instanceof HTMLCollection||t instanceof NodeList?t:[t]:((0,YO.default)(!1,["react-modal: App element is not defined.","Please use `Modal.setAppElement(el)` or set `appElement={el}`.","This is needed so screen readers don't see main content","when modal is opened. It is not recommended, but you can opt-out","by setting `ariaHideApp={false}`."].join(" ")),[])}function ZO(e){var t=!0,n=!1,r=void 0;try{for(var o=Ih(e)[Symbol.iterator](),i;!(t=(i=o.next()).done);t=!0){var a=i.value;a.setAttribute("aria-hidden","true")}}catch(l){n=!0,r=l}finally{try{!t&&o.return&&o.return()}finally{if(n)throw r}}}function JO(e){var t=!0,n=!1,r=void 0;try{for(var o=Ih(e)[Symbol.iterator](),i;!(t=(i=o.next()).done);t=!0){var a=i.value;a.removeAttribute("aria-hidden")}}catch(l){n=!0,r=l}finally{try{!t&&o.return&&o.return()}finally{if(n)throw r}}}function eR(){fr=null}var el={};Object.defineProperty(el,"__esModule",{value:!0});el.resetState=tR;el.log=nR;var Ul={},Yl={};function q0(e,t){e.classList.remove(t)}function tR(){var e=document.getElementsByTagName("html")[0];for(var t in Ul)q0(e,Ul[t]);var n=document.body;for(var r in Yl)q0(n,Yl[r]);Ul={},Yl={}}function nR(){}var rR=function(t,n){return t[n]||(t[n]=0),t[n]+=1,n},oR=function(t,n){return t[n]&&(t[n]-=1),n},iR=function(t,n,r){r.forEach(function(o){rR(n,o),t.add(o)})},aR=function(t,n,r){r.forEach(function(o){oR(n,o),n[o]===0&&t.remove(o)})};el.add=function(t,n){return iR(t.classList,t.nodeName.toLowerCase()=="html"?Ul:Yl,n.split(" "))};el.remove=function(t,n){return aR(t.classList,t.nodeName.toLowerCase()=="html"?Ul:Yl,n.split(" "))};var tl={};Object.defineProperty(tl,"__esModule",{value:!0});tl.log=sR;tl.resetState=cR;function lR(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var kC=function e(){var t=this;lR(this,e),this.register=function(n){t.openInstances.indexOf(n)===-1&&(t.openInstances.push(n),t.emit("register"))},this.deregister=function(n){var r=t.openInstances.indexOf(n);r!==-1&&(t.openInstances.splice(r,1),t.emit("deregister"))},this.subscribe=function(n){t.subscribers.push(n)},this.emit=function(n){t.subscribers.forEach(function(r){return r(n,t.openInstances.slice())})},this.openInstances=[],this.subscribers=[]},ku=new kC;function sR(){console.log("portalOpenInstances ----------"),console.log(ku.openInstances.length),ku.openInstances.forEach(function(e){return console.log(e)}),console.log("end portalOpenInstances ----------")}function cR(){ku=new kC}tl.default=ku;var Ph={};Object.defineProperty(Ph,"__esModule",{value:!0});Ph.resetState=vR;Ph.log=pR;var uR=tl,dR=fR(uR);function fR(e){return e&&e.__esModule?e:{default:e}}var wn=void 0,Ir=void 0,Ei=[];function vR(){for(var e=[wn,Ir],t=0;t0?(document.body.firstChild!==wn&&document.body.insertBefore(wn,document.body.firstChild),document.body.lastChild!==Ir&&document.body.appendChild(Ir)):(wn.parentElement&&wn.parentElement.removeChild(wn),Ir.parentElement&&Ir.parentElement.removeChild(Ir))}dR.default.subscribe(gR);(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var n=Object.assign||function(T){for(var D=1;D0&&(z-=1,z===0&&h.show(L)),O.props.shouldFocusAfterRender&&(O.props.shouldReturnFocusAfterClose?(c.returnFocus(O.props.preventScroll),c.teardownScopedFocus()):c.popWithoutFocus()),O.props.onAfterClose&&O.props.onAfterClose(),S.default.deregister(O)},O.open=function(){O.beforeOpen(),O.state.afterOpen&&O.state.beforeClose?(clearTimeout(O.closeTimer),O.setState({beforeClose:!1})):(O.props.shouldFocusAfterRender&&(c.setupScopedFocus(O.node),c.markForFocusLater()),O.setState({isOpen:!0},function(){O.openAnimationFrame=requestAnimationFrame(function(){O.setState({afterOpen:!0}),O.props.isOpen&&O.props.onAfterOpen&&O.props.onAfterOpen({overlayEl:O.overlay,contentEl:O.content})})}))},O.close=function(){O.props.closeTimeoutMS>0?O.closeWithTimeout():O.closeWithoutTimeout()},O.focusContent=function(){return O.content&&!O.contentHasFocus()&&O.content.focus({preventScroll:!0})},O.closeWithTimeout=function(){var M=Date.now()+O.props.closeTimeoutMS;O.setState({beforeClose:!0,closesAt:M},function(){O.closeTimer=setTimeout(O.closeWithoutTimeout,O.state.closesAt-Date.now())})},O.closeWithoutTimeout=function(){O.setState({beforeClose:!1,isOpen:!1,afterOpen:!1,closesAt:null},O.afterClose)},O.handleKeyDown=function(M){N(M)&&(0,d.default)(O.content,M),O.props.shouldCloseOnEsc&&I(M)&&(M.stopPropagation(),O.requestClose(M))},O.handleOverlayOnClick=function(M){O.shouldClose===null&&(O.shouldClose=!0),O.shouldClose&&O.props.shouldCloseOnOverlayClick&&(O.ownerHandlesClose()?O.requestClose(M):O.focusContent()),O.shouldClose=null},O.handleContentOnMouseUp=function(){O.shouldClose=!1},O.handleOverlayOnMouseDown=function(M){!O.props.shouldCloseOnOverlayClick&&M.target==O.overlay&&M.preventDefault()},O.handleContentOnClick=function(){O.shouldClose=!1},O.handleContentOnMouseDown=function(){O.shouldClose=!1},O.requestClose=function(M){return O.ownerHandlesClose()&&O.props.onRequestClose(M)},O.ownerHandlesClose=function(){return O.props.onRequestClose},O.shouldBeClosed=function(){return!O.state.isOpen&&!O.state.beforeClose},O.contentHasFocus=function(){return document.activeElement===O.content||O.content.contains(document.activeElement)},O.buildClassName=function(M,L){var A=(typeof L>"u"?"undefined":r(L))==="object"?L:{base:P[M],afterOpen:P[M]+"--after-open",beforeClose:P[M]+"--before-close"},B=A.base;return O.state.afterOpen&&(B=B+" "+A.afterOpen),O.state.beforeClose&&(B=B+" "+A.beforeClose),typeof L=="string"&&L?B+" "+L:B},O.attributesFromObject=function(M,L){return Object.keys(L).reduce(function(A,B){return A[M+"-"+B]=L[B],A},{})},O.state={afterOpen:!1,beforeClose:!1},O.shouldClose=null,O.moveFromContentToOverlay=null,O}return o(D,[{key:"componentDidMount",value:function(){this.props.isOpen&&this.open()}},{key:"componentDidUpdate",value:function(O,M){this.props.isOpen&&!O.isOpen?this.open():!this.props.isOpen&&O.isOpen&&this.close(),this.props.shouldFocusAfterRender&&this.state.isOpen&&!M.isOpen&&this.focusContent()}},{key:"componentWillUnmount",value:function(){this.state.isOpen&&this.afterClose(),clearTimeout(this.closeTimer),cancelAnimationFrame(this.openAnimationFrame)}},{key:"beforeOpen",value:function(){var O=this.props,M=O.appElement,L=O.ariaHideApp,A=O.htmlOpenClassName,B=O.bodyOpenClassName,k=O.parentSelector,j=k&&k().ownerDocument||document;B&&p.add(j.body,B),A&&p.add(j.getElementsByTagName("html")[0],A),L&&(z+=1,h.hide(M)),S.default.register(this)}},{key:"render",value:function(){var O=this.props,M=O.id,L=O.className,A=O.overlayClassName,B=O.defaultStyles,k=O.children,j=L?{}:B.content,H=A?{}:B.overlay;if(this.shouldBeClosed())return null;var W={ref:this.setOverlayRef,className:this.buildClassName("overlay",A),style:n({},H,this.props.style.overlay),onClick:this.handleOverlayOnClick,onMouseDown:this.handleOverlayOnMouseDown},Y=n({id:M,ref:this.setContentRef,style:n({},j,this.props.style.content),className:this.buildClassName("content",L),tabIndex:"-1",onKeyDown:this.handleKeyDown,onMouseDown:this.handleContentOnMouseDown,onMouseUp:this.handleContentOnMouseUp,onClick:this.handleContentOnClick,role:this.props.role,"aria-label":this.props.contentLabel},this.attributesFromObject("aria",n({modal:!0},this.props.aria)),this.attributesFromObject("data",this.props.data||{}),{"data-testid":this.props.testId}),K=this.props.contentElement(Y,k);return this.props.overlayElement(W,K)}}]),D}(i.Component);F.defaultProps={style:{overlay:{},content:{}},defaultStyles:{}},F.propTypes={isOpen:l.default.bool.isRequired,defaultStyles:l.default.shape({content:l.default.object,overlay:l.default.object}),style:l.default.shape({content:l.default.object,overlay:l.default.object}),className:l.default.oneOfType([l.default.string,l.default.object]),overlayClassName:l.default.oneOfType([l.default.string,l.default.object]),parentSelector:l.default.func,bodyOpenClassName:l.default.string,htmlOpenClassName:l.default.string,ariaHideApp:l.default.bool,appElement:l.default.oneOfType([l.default.instanceOf(m.default),l.default.instanceOf(b.SafeHTMLCollection),l.default.instanceOf(b.SafeNodeList),l.default.arrayOf(l.default.instanceOf(m.default))]),onAfterOpen:l.default.func,onAfterClose:l.default.func,onRequestClose:l.default.func,closeTimeoutMS:l.default.number,shouldFocusAfterRender:l.default.bool,shouldCloseOnOverlayClick:l.default.bool,shouldReturnFocusAfterClose:l.default.bool,preventScroll:l.default.bool,role:l.default.string,contentLabel:l.default.string,aria:l.default.object,data:l.default.object,children:l.default.node,shouldCloseOnEsc:l.default.bool,overlayRef:l.default.func,contentRef:l.default.func,id:l.default.string,overlayElement:l.default.func,contentElement:l.default.func,testId:l.default.string},t.default=F,e.exports=t.default})(Ep,Ep.exports);function BC(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);e!=null&&this.setState(e)}function jC(e){function t(n){var r=this.constructor.getDerivedStateFromProps(e,n);return r!=null?r:null}this.setState(t.bind(this))}function HC(e,t){try{var n=this.props,r=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,r)}finally{this.props=n,this.state=r}}BC.__suppressDeprecationWarning=!0;jC.__suppressDeprecationWarning=!0;HC.__suppressDeprecationWarning=!0;function hR(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if(typeof e.getDerivedStateFromProps!="function"&&typeof t.getSnapshotBeforeUpdate!="function")return e;var n=null,r=null,o=null;if(typeof t.componentWillMount=="function"?n="componentWillMount":typeof t.UNSAFE_componentWillMount=="function"&&(n="UNSAFE_componentWillMount"),typeof t.componentWillReceiveProps=="function"?r="componentWillReceiveProps":typeof t.UNSAFE_componentWillReceiveProps=="function"&&(r="UNSAFE_componentWillReceiveProps"),typeof t.componentWillUpdate=="function"?o="componentWillUpdate":typeof t.UNSAFE_componentWillUpdate=="function"&&(o="UNSAFE_componentWillUpdate"),n!==null||r!==null||o!==null){var i=e.displayName||e.name,a=typeof e.getDerivedStateFromProps=="function"?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()";throw Error(`Unsafe legacy lifecycles will not be called for components using new component APIs. + +`+i+" uses "+a+" but also contains the following legacy lifecycles:"+(n!==null?` + `+n:"")+(r!==null?` + `+r:"")+(o!==null?` + `+o:"")+` + +The above lifecycles should be removed. Learn more about this warning here: +https://fb.me/react-async-component-lifecycle-hooks`)}if(typeof e.getDerivedStateFromProps=="function"&&(t.componentWillMount=BC,t.componentWillReceiveProps=jC),typeof t.getSnapshotBeforeUpdate=="function"){if(typeof t.componentDidUpdate!="function")throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=HC;var l=t.componentDidUpdate;t.componentDidUpdate=function(c,u,d){var v=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:d;l.call(this,c,u,v)}}return e}const mR=Object.freeze(Object.defineProperty({__proto__:null,polyfill:hR},Symbol.toStringTag,{value:"Module"})),yR=aE(mR);Object.defineProperty(_i,"__esModule",{value:!0});_i.bodyOpenClassName=_i.portalClassName=void 0;var Q0=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0)&&(n[o]=e[o]);return n}function Je(e,t){if(e==null)return{};var n=AR(e,t),r,o;if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0)&&(!Object.prototype.propertyIsEnumerable.call(e,r)||(n[r]=e[r]))}return n}var GC={exports:{}};/*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/(function(e){(function(){var t={}.hasOwnProperty;function n(){for(var i="",a=0;a1)&&(e=1),e}function wc(e){return e<=1?"".concat(Number(e)*100,"%"):e}function bi(e){return e.length===1?"0"+e:String(e)}function zR(e,t,n){return{r:bn(e,255)*255,g:bn(t,255)*255,b:bn(n,255)*255}}function ry(e,t,n){e=bn(e,255),t=bn(t,255),n=bn(n,255);var r=Math.max(e,t,n),o=Math.min(e,t,n),i=0,a=0,l=(r+o)/2;if(r===o)a=0,i=0;else{var s=r-o;switch(a=l>.5?s/(2-r-o):s/(r+o),r){case e:i=(t-n)/s+(t1&&(n-=1),n<1/6?e+(t-e)*(6*n):n<1/2?t:n<2/3?e+(t-e)*(2/3-n)*6:e}function FR(e,t,n){var r,o,i;if(e=bn(e,360),t=bn(t,100),n=bn(n,100),t===0)o=n,i=n,r=n;else{var a=n<.5?n*(1+t):n+t-n*t,l=2*n-a;r=qf(l,a,e+1/3),o=qf(l,a,e),i=qf(l,a,e-1/3)}return{r:r*255,g:o*255,b:i*255}}function Ip(e,t,n){e=bn(e,255),t=bn(t,255),n=bn(n,255);var r=Math.max(e,t,n),o=Math.min(e,t,n),i=0,a=r,l=r-o,s=r===0?0:l/r;if(r===o)i=0;else{switch(r){case e:i=(t-n)/l+(t>16,g:(e&65280)>>8,b:e&255}}var Tp={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",goldenrod:"#daa520",gold:"#ffd700",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavenderblush:"#fff0f5",lavender:"#e6e6fa",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};function la(e){var t={r:0,g:0,b:0},n=1,r=null,o=null,i=null,a=!1,l=!1;return typeof e=="string"&&(e=UR(e)),typeof e=="object"&&(oo(e.r)&&oo(e.g)&&oo(e.b)?(t=zR(e.r,e.g,e.b),a=!0,l=String(e.r).substr(-1)==="%"?"prgb":"rgb"):oo(e.h)&&oo(e.s)&&oo(e.v)?(r=wc(e.s),o=wc(e.v),t=kR(e.h,r,o),a=!0,l="hsv"):oo(e.h)&&oo(e.s)&&oo(e.l)&&(r=wc(e.s),i=wc(e.l),t=FR(e.h,r,i),a=!0,l="hsl"),Object.prototype.hasOwnProperty.call(e,"a")&&(n=e.a)),n=KC(n),{ok:a,format:e.format||l,r:Math.min(255,Math.max(t.r,0)),g:Math.min(255,Math.max(t.g,0)),b:Math.min(255,Math.max(t.b,0)),a:n}}var WR="[-\\+]?\\d+%?",VR="[-\\+]?\\d*\\.\\d+%?",Do="(?:".concat(VR,")|(?:").concat(WR,")"),Xf="[\\s|\\(]+(".concat(Do,")[,|\\s]+(").concat(Do,")[,|\\s]+(").concat(Do,")\\s*\\)?"),Qf="[\\s|\\(]+(".concat(Do,")[,|\\s]+(").concat(Do,")[,|\\s]+(").concat(Do,")[,|\\s]+(").concat(Do,")\\s*\\)?"),Or={CSS_UNIT:new RegExp(Do),rgb:new RegExp("rgb"+Xf),rgba:new RegExp("rgba"+Qf),hsl:new RegExp("hsl"+Xf),hsla:new RegExp("hsla"+Qf),hsv:new RegExp("hsv"+Xf),hsva:new RegExp("hsva"+Qf),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/};function UR(e){if(e=e.trim().toLowerCase(),e.length===0)return!1;var t=!1;if(Tp[e])e=Tp[e],t=!0;else if(e==="transparent")return{r:0,g:0,b:0,a:0,format:"name"};var n=Or.rgb.exec(e);return n?{r:n[1],g:n[2],b:n[3]}:(n=Or.rgba.exec(e),n?{r:n[1],g:n[2],b:n[3],a:n[4]}:(n=Or.hsl.exec(e),n?{h:n[1],s:n[2],l:n[3]}:(n=Or.hsla.exec(e),n?{h:n[1],s:n[2],l:n[3],a:n[4]}:(n=Or.hsv.exec(e),n?{h:n[1],s:n[2],v:n[3]}:(n=Or.hsva.exec(e),n?{h:n[1],s:n[2],v:n[3],a:n[4]}:(n=Or.hex8.exec(e),n?{r:Jn(n[1]),g:Jn(n[2]),b:Jn(n[3]),a:oy(n[4]),format:t?"name":"hex8"}:(n=Or.hex6.exec(e),n?{r:Jn(n[1]),g:Jn(n[2]),b:Jn(n[3]),format:t?"name":"hex"}:(n=Or.hex4.exec(e),n?{r:Jn(n[1]+n[1]),g:Jn(n[2]+n[2]),b:Jn(n[3]+n[3]),a:oy(n[4]+n[4]),format:t?"name":"hex8"}:(n=Or.hex3.exec(e),n?{r:Jn(n[1]+n[1]),g:Jn(n[2]+n[2]),b:Jn(n[3]+n[3]),format:t?"name":"hex"}:!1)))))))))}function oo(e){return Boolean(Or.CSS_UNIT.exec(String(e)))}var Mt=function(){function e(t,n){t===void 0&&(t=""),n===void 0&&(n={});var r;if(t instanceof e)return t;typeof t=="number"&&(t=HR(t)),this.originalInput=t;var o=la(t);this.originalInput=t,this.r=o.r,this.g=o.g,this.b=o.b,this.a=o.a,this.roundA=Math.round(100*this.a)/100,this.format=(r=n.format)!==null&&r!==void 0?r:o.format,this.gradientType=n.gradientType,this.r<1&&(this.r=Math.round(this.r)),this.g<1&&(this.g=Math.round(this.g)),this.b<1&&(this.b=Math.round(this.b)),this.isValid=o.ok}return e.prototype.isDark=function(){return this.getBrightness()<128},e.prototype.isLight=function(){return!this.isDark()},e.prototype.getBrightness=function(){var t=this.toRgb();return(t.r*299+t.g*587+t.b*114)/1e3},e.prototype.getLuminance=function(){var t=this.toRgb(),n,r,o,i=t.r/255,a=t.g/255,l=t.b/255;return i<=.03928?n=i/12.92:n=Math.pow((i+.055)/1.055,2.4),a<=.03928?r=a/12.92:r=Math.pow((a+.055)/1.055,2.4),l<=.03928?o=l/12.92:o=Math.pow((l+.055)/1.055,2.4),.2126*n+.7152*r+.0722*o},e.prototype.getAlpha=function(){return this.a},e.prototype.setAlpha=function(t){return this.a=KC(t),this.roundA=Math.round(100*this.a)/100,this},e.prototype.isMonochrome=function(){var t=this.toHsl().s;return t===0},e.prototype.toHsv=function(){var t=Ip(this.r,this.g,this.b);return{h:t.h*360,s:t.s,v:t.v,a:this.a}},e.prototype.toHsvString=function(){var t=Ip(this.r,this.g,this.b),n=Math.round(t.h*360),r=Math.round(t.s*100),o=Math.round(t.v*100);return this.a===1?"hsv(".concat(n,", ").concat(r,"%, ").concat(o,"%)"):"hsva(".concat(n,", ").concat(r,"%, ").concat(o,"%, ").concat(this.roundA,")")},e.prototype.toHsl=function(){var t=ry(this.r,this.g,this.b);return{h:t.h*360,s:t.s,l:t.l,a:this.a}},e.prototype.toHslString=function(){var t=ry(this.r,this.g,this.b),n=Math.round(t.h*360),r=Math.round(t.s*100),o=Math.round(t.l*100);return this.a===1?"hsl(".concat(n,", ").concat(r,"%, ").concat(o,"%)"):"hsla(".concat(n,", ").concat(r,"%, ").concat(o,"%, ").concat(this.roundA,")")},e.prototype.toHex=function(t){return t===void 0&&(t=!1),Pp(this.r,this.g,this.b,t)},e.prototype.toHexString=function(t){return t===void 0&&(t=!1),"#"+this.toHex(t)},e.prototype.toHex8=function(t){return t===void 0&&(t=!1),BR(this.r,this.g,this.b,this.a,t)},e.prototype.toHex8String=function(t){return t===void 0&&(t=!1),"#"+this.toHex8(t)},e.prototype.toHexShortString=function(t){return t===void 0&&(t=!1),this.a===1?this.toHexString(t):this.toHex8String(t)},e.prototype.toRgb=function(){return{r:Math.round(this.r),g:Math.round(this.g),b:Math.round(this.b),a:this.a}},e.prototype.toRgbString=function(){var t=Math.round(this.r),n=Math.round(this.g),r=Math.round(this.b);return this.a===1?"rgb(".concat(t,", ").concat(n,", ").concat(r,")"):"rgba(".concat(t,", ").concat(n,", ").concat(r,", ").concat(this.roundA,")")},e.prototype.toPercentageRgb=function(){var t=function(n){return"".concat(Math.round(bn(n,255)*100),"%")};return{r:t(this.r),g:t(this.g),b:t(this.b),a:this.a}},e.prototype.toPercentageRgbString=function(){var t=function(n){return Math.round(bn(n,255)*100)};return this.a===1?"rgb(".concat(t(this.r),"%, ").concat(t(this.g),"%, ").concat(t(this.b),"%)"):"rgba(".concat(t(this.r),"%, ").concat(t(this.g),"%, ").concat(t(this.b),"%, ").concat(this.roundA,")")},e.prototype.toName=function(){if(this.a===0)return"transparent";if(this.a<1)return!1;for(var t="#"+Pp(this.r,this.g,this.b,!1),n=0,r=Object.entries(Tp);n=0,i=!n&&o&&(t.startsWith("hex")||t==="name");return i?t==="name"&&this.a===0?this.toName():this.toRgbString():(t==="rgb"&&(r=this.toRgbString()),t==="prgb"&&(r=this.toPercentageRgbString()),(t==="hex"||t==="hex6")&&(r=this.toHexString()),t==="hex3"&&(r=this.toHexString(!0)),t==="hex4"&&(r=this.toHex8String(!0)),t==="hex8"&&(r=this.toHex8String()),t==="name"&&(r=this.toName()),t==="hsl"&&(r=this.toHslString()),t==="hsv"&&(r=this.toHsvString()),r||this.toHexString())},e.prototype.toNumber=function(){return(Math.round(this.r)<<16)+(Math.round(this.g)<<8)+Math.round(this.b)},e.prototype.clone=function(){return new e(this.toString())},e.prototype.lighten=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.l+=t/100,n.l=xc(n.l),new e(n)},e.prototype.brighten=function(t){t===void 0&&(t=10);var n=this.toRgb();return n.r=Math.max(0,Math.min(255,n.r-Math.round(255*-(t/100)))),n.g=Math.max(0,Math.min(255,n.g-Math.round(255*-(t/100)))),n.b=Math.max(0,Math.min(255,n.b-Math.round(255*-(t/100)))),new e(n)},e.prototype.darken=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.l-=t/100,n.l=xc(n.l),new e(n)},e.prototype.tint=function(t){return t===void 0&&(t=10),this.mix("white",t)},e.prototype.shade=function(t){return t===void 0&&(t=10),this.mix("black",t)},e.prototype.desaturate=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.s-=t/100,n.s=xc(n.s),new e(n)},e.prototype.saturate=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.s+=t/100,n.s=xc(n.s),new e(n)},e.prototype.greyscale=function(){return this.desaturate(100)},e.prototype.spin=function(t){var n=this.toHsl(),r=(n.h+t)%360;return n.h=r<0?360+r:r,new e(n)},e.prototype.mix=function(t,n){n===void 0&&(n=50);var r=this.toRgb(),o=new e(t).toRgb(),i=n/100,a={r:(o.r-r.r)*i+r.r,g:(o.g-r.g)*i+r.g,b:(o.b-r.b)*i+r.b,a:(o.a-r.a)*i+r.a};return new e(a)},e.prototype.analogous=function(t,n){t===void 0&&(t=6),n===void 0&&(n=30);var r=this.toHsl(),o=360/n,i=[this];for(r.h=(r.h-(o*t>>1)+720)%360;--t;)r.h=(r.h+o)%360,i.push(new e(r));return i},e.prototype.complement=function(){var t=this.toHsl();return t.h=(t.h+180)%360,new e(t)},e.prototype.monochromatic=function(t){t===void 0&&(t=6);for(var n=this.toHsv(),r=n.h,o=n.s,i=n.v,a=[],l=1/t;t--;)a.push(new e({h:r,s:o,v:i})),i=(i+l)%1;return a},e.prototype.splitcomplement=function(){var t=this.toHsl(),n=t.h;return[this,new e({h:(n+72)%360,s:t.s,l:t.l}),new e({h:(n+216)%360,s:t.s,l:t.l})]},e.prototype.onBackground=function(t){var n=this.toRgb(),r=new e(t).toRgb(),o=n.a+r.a*(1-n.a);return new e({r:(n.r*n.a+r.r*r.a*(1-n.a))/o,g:(n.g*n.a+r.g*r.a*(1-n.a))/o,b:(n.b*n.a+r.b*r.a*(1-n.a))/o,a:o})},e.prototype.triad=function(){return this.polyad(3)},e.prototype.tetrad=function(){return this.polyad(4)},e.prototype.polyad=function(t){for(var n=this.toHsl(),r=n.h,o=[this],i=360/t,a=1;a=60&&Math.round(e.h)<=240?r=n?Math.round(e.h)-$c*t:Math.round(e.h)+$c*t:r=n?Math.round(e.h)+$c*t:Math.round(e.h)-$c*t,r<0?r+=360:r>=360&&(r-=360),r}function sy(e,t,n){if(e.h===0&&e.s===0)return e.s;var r;return n?r=e.s-iy*t:t===XC?r=e.s+iy:r=e.s+YR*t,r>1&&(r=1),n&&t===qC&&r>.1&&(r=.1),r<.06&&(r=.06),Number(r.toFixed(2))}function cy(e,t,n){var r;return n?r=e.v+GR*t:r=e.v-KR*t,r>1&&(r=1),Number(r.toFixed(2))}function Ai(e){for(var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=[],r=la(e),o=qC;o>0;o-=1){var i=ay(r),a=Ec(la({h:ly(i,o,!0),s:sy(i,o,!0),v:cy(i,o,!0)}));n.push(a)}n.push(Ec(r));for(var l=1;l<=XC;l+=1){var s=ay(r),c=Ec(la({h:ly(s,l),s:sy(s,l),v:cy(s,l)}));n.push(c)}return t.theme==="dark"?qR.map(function(u){var d=u.index,v=u.opacity,h=Ec(XR(la(t.backgroundColor||"#141414"),la(n[d]),v*100));return h}):n}var Na={red:"#F5222D",volcano:"#FA541C",orange:"#FA8C16",gold:"#FAAD14",yellow:"#FADB14",lime:"#A0D911",green:"#52C41A",cyan:"#13C2C2",blue:"#1677FF",geekblue:"#2F54EB",purple:"#722ED1",magenta:"#EB2F96",grey:"#666666"},Jc={},Zf={};Object.keys(Na).forEach(function(e){Jc[e]=Ai(Na[e]),Jc[e].primary=Jc[e][5],Zf[e]=Ai(Na[e],{theme:"dark",backgroundColor:"#141414"}),Zf[e].primary=Zf[e][5]});var QR=Jc.blue;function uy(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(e,o).enumerable})),n.push.apply(n,r)}return n}function U(e){for(var t=1;t0&&arguments[0]!==void 0?arguments[0]:{},t=e.mark;return t?t.startsWith("data-")?t:"data-".concat(t):ZR}function Od(e){if(e.attachTo)return e.attachTo;var t=document.querySelector("head");return t||document.body}function JR(e){return e==="queue"?"prependQueue":e?"prepend":"append"}function _h(e){return Array.from((_p.get(e)||e).children).filter(function(t){return t.tagName==="STYLE"})}function ZC(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(!Rn())return null;var n=t.csp,r=t.prepend,o=t.priority,i=o===void 0?0:o,a=JR(r),l=a==="prependQueue",s=document.createElement("style");s.setAttribute(dy,a),l&&i&&s.setAttribute(fy,"".concat(i)),n!=null&&n.nonce&&(s.nonce=n==null?void 0:n.nonce),s.innerHTML=e;var c=Od(t),u=c.firstChild;if(r){if(l){var d=(t.styles||_h(c)).filter(function(v){if(!["prepend","prependQueue"].includes(v.getAttribute(dy)))return!1;var h=Number(v.getAttribute(fy)||0);return i>=h});if(d.length)return c.insertBefore(s,d[d.length-1].nextSibling),s}c.insertBefore(s,u)}else c.appendChild(s);return s}function JC(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=Od(t);return(t.styles||_h(n)).find(function(r){return r.getAttribute(QC(t))===e})}function Ss(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=JC(e,t);if(n){var r=Od(t);r.removeChild(n)}}function eI(e,t){var n=_p.get(e);if(!n||!Np(document,n)){var r=ZC("",t),o=r.parentNode;_p.set(e,o),e.removeChild(r)}}function Xo(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=Od(n),o=_h(r),i=U(U({},n),{},{styles:o});eI(r,i);var a=JC(t,i);if(a){var l,s;if((l=i.csp)!==null&&l!==void 0&&l.nonce&&a.nonce!==((s=i.csp)===null||s===void 0?void 0:s.nonce)){var c;a.nonce=(c=i.csp)===null||c===void 0?void 0:c.nonce}return a.innerHTML!==e&&(a.innerHTML=e),a}var u=ZC(e,i);return u.setAttribute(QC(i),t),u}function ex(e){var t;return e==null||(t=e.getRootNode)===null||t===void 0?void 0:t.call(e)}function tI(e){return ex(e)instanceof ShadowRoot}function Hu(e){return tI(e)?ex(e):null}var Ap={},nI=function(t){};function rI(e,t){}function oI(e,t){}function iI(){Ap={}}function tx(e,t,n){!t&&!Ap[n]&&(e(!1,n),Ap[n]=!0)}function Mn(e,t){tx(rI,e,t)}function nx(e,t){tx(oI,e,t)}Mn.preMessage=nI;Mn.resetWarned=iI;Mn.noteOnce=nx;function aI(e){return e.replace(/-(.)/g,function(t,n){return n.toUpperCase()})}function lI(e,t){Mn(e,"[@ant-design/icons] ".concat(t))}function vy(e){return Qe(e)==="object"&&typeof e.name=="string"&&typeof e.theme=="string"&&(Qe(e.icon)==="object"||typeof e.icon=="function")}function py(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return Object.keys(e).reduce(function(t,n){var r=e[n];switch(n){case"class":t.className=r,delete t.class;break;default:delete t[n],t[aI(n)]=r}return t},{})}function Dp(e,t,n){return n?lt.createElement(e.tag,U(U({key:t},py(e.attrs)),n),(e.children||[]).map(function(r,o){return Dp(r,"".concat(t,"-").concat(e.tag,"-").concat(o))})):lt.createElement(e.tag,U({key:t},py(e.attrs)),(e.children||[]).map(function(r,o){return Dp(r,"".concat(t,"-").concat(e.tag,"-").concat(o))}))}function rx(e){return Ai(e)[0]}function ox(e){return e?Array.isArray(e)?e:[e]:[]}var sI=` +.anticon { + display: inline-block; + color: inherit; + font-style: normal; + line-height: 0; + text-align: center; + text-transform: none; + vertical-align: -0.125em; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.anticon > * { + line-height: 1; +} + +.anticon svg { + display: inline-block; +} + +.anticon::before { + display: none; +} + +.anticon .anticon-icon { + display: block; +} + +.anticon[tabindex] { + cursor: pointer; +} + +.anticon-spin::before, +.anticon-spin { + display: inline-block; + -webkit-animation: loadingCircle 1s infinite linear; + animation: loadingCircle 1s infinite linear; +} + +@-webkit-keyframes loadingCircle { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes loadingCircle { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +`,cI=function(t){var n=f.exports.useContext(Th),r=n.csp,o=n.prefixCls,i=sI;o&&(i=i.replace(/anticon/g,o)),f.exports.useEffect(function(){var a=t.current,l=Hu(a);Xo(i,"@ant-design-icons",{prepend:!0,csp:r,attachTo:l})},[])},uI=["icon","className","onClick","style","primaryColor","secondaryColor"],Gl={primaryColor:"#333",secondaryColor:"#E6E6E6",calculated:!1};function dI(e){var t=e.primaryColor,n=e.secondaryColor;Gl.primaryColor=t,Gl.secondaryColor=n||rx(t),Gl.calculated=!!n}function fI(){return U({},Gl)}var Rd=function(t){var n=t.icon,r=t.className,o=t.onClick,i=t.style,a=t.primaryColor,l=t.secondaryColor,s=Je(t,uI),c=f.exports.useRef(),u=Gl;if(a&&(u={primaryColor:a,secondaryColor:l||rx(a)}),cI(c),lI(vy(n),"icon should be icon definiton, but got ".concat(n)),!vy(n))return null;var d=n;return d&&typeof d.icon=="function"&&(d=U(U({},d),{},{icon:d.icon(u.primaryColor,u.secondaryColor)})),Dp(d.icon,"svg-".concat(d.name),U(U({className:r,onClick:o,style:i,"data-icon":d.name,width:"1em",height:"1em",fill:"currentColor","aria-hidden":"true"},s),{},{ref:c}))};Rd.displayName="IconReact";Rd.getTwoToneColors=fI;Rd.setTwoToneColors=dI;const Ah=Rd;function ix(e){var t=ox(e),n=G(t,2),r=n[0],o=n[1];return Ah.setTwoToneColors({primaryColor:r,secondaryColor:o})}function vI(){var e=Ah.getTwoToneColors();return e.calculated?[e.primaryColor,e.secondaryColor]:e.primaryColor}var Id={exports:{}},Pd={};/** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var pI=f.exports,gI=Symbol.for("react.element"),hI=Symbol.for("react.fragment"),mI=Object.prototype.hasOwnProperty,yI=pI.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,bI={key:!0,ref:!0,__self:!0,__source:!0};function ax(e,t,n){var r,o={},i=null,a=null;n!==void 0&&(i=""+n),t.key!==void 0&&(i=""+t.key),t.ref!==void 0&&(a=t.ref);for(r in t)mI.call(t,r)&&!bI.hasOwnProperty(r)&&(o[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)o[r]===void 0&&(o[r]=t[r]);return{$$typeof:gI,type:e,key:i,ref:a,props:o,_owner:yI.current}}Pd.Fragment=hI;Pd.jsx=ax;Pd.jsxs=ax;(function(e){e.exports=Pd})(Id);const Tt=Id.exports.Fragment,C=Id.exports.jsx,ie=Id.exports.jsxs;var SI=["className","icon","spin","rotate","tabIndex","onClick","twoToneColor"];ix(QR.primary);var Td=f.exports.forwardRef(function(e,t){var n=e.className,r=e.icon,o=e.spin,i=e.rotate,a=e.tabIndex,l=e.onClick,s=e.twoToneColor,c=Je(e,SI),u=f.exports.useContext(Th),d=u.prefixCls,v=d===void 0?"anticon":d,h=u.rootClassName,g=te(h,v,V(V({},"".concat(v,"-").concat(r.name),!!r.name),"".concat(v,"-spin"),!!o||r.name==="loading"),n),p=a;p===void 0&&l&&(p=-1);var b=i?{msTransform:"rotate(".concat(i,"deg)"),transform:"rotate(".concat(i,"deg)")}:void 0,m=ox(s),y=G(m,2),S=y[0],x=y[1];return C("span",{role:"img","aria-label":r.name,...c,ref:t,tabIndex:p,onClick:l,className:g,children:C(Ah,{icon:r,primaryColor:S,secondaryColor:x,style:b})})});Td.displayName="AntdIcon";Td.getTwoToneColor=vI;Td.setTwoToneColor=ix;const Et=Td;var CI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"}}]},name:"appstore",theme:"outlined"};const xI=CI;var wI=function(t,n){return C(Et,{...t,ref:n,icon:xI})};const $I=f.exports.forwardRef(wI);var EI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"}}]},name:"audio",theme:"outlined"};const MI=EI;var OI=function(t,n){return C(Et,{...t,ref:n,icon:MI})};const RI=f.exports.forwardRef(OI);var II={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"}}]},name:"check-circle",theme:"filled"};const PI=II;var TI=function(t,n){return C(Et,{...t,ref:n,icon:PI})};const NI=f.exports.forwardRef(TI);var _I={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"}}]},name:"check",theme:"outlined"};const AI=_I;var DI=function(t,n){return C(Et,{...t,ref:n,icon:AI})};const lx=f.exports.forwardRef(DI);var LI={icon:{tag:"svg",attrs:{"fill-rule":"evenodd",viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"}}]},name:"close-circle",theme:"filled"};const zI=LI;var FI=function(t,n){return C(Et,{...t,ref:n,icon:zI})};const Nd=f.exports.forwardRef(FI);var kI={icon:{tag:"svg",attrs:{"fill-rule":"evenodd",viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"}}]},name:"close",theme:"outlined"};const BI=kI;var jI=function(t,n){return C(Et,{...t,ref:n,icon:BI})};const eo=f.exports.forwardRef(jI);var HI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM288 604a64 64 0 10128 0 64 64 0 10-128 0zm118-224a48 48 0 1096 0 48 48 0 10-96 0zm158 228a96 96 0 10192 0 96 96 0 10-192 0zm148-314a56 56 0 10112 0 56 56 0 10-112 0z"}}]},name:"dot-chart",theme:"outlined"};const WI=HI;var VI=function(t,n){return C(Et,{...t,ref:n,icon:WI})};const UI=f.exports.forwardRef(VI);var YI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"}}]},name:"down",theme:"outlined"};const GI=YI;var KI=function(t,n){return C(Et,{...t,ref:n,icon:GI})};const qI=f.exports.forwardRef(KI);var XI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"}}]},name:"ellipsis",theme:"outlined"};const QI=XI;var ZI=function(t,n){return C(Et,{...t,ref:n,icon:QI})};const JI=f.exports.forwardRef(ZI);var eP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"}},{tag:"path",attrs:{d:"M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"}}]},name:"eye-invisible",theme:"outlined"};const tP=eP;var nP=function(t,n){return C(Et,{...t,ref:n,icon:tP})};const rP=f.exports.forwardRef(nP);var oP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"}}]},name:"eye",theme:"outlined"};const iP=oP;var aP=function(t,n){return C(Et,{...t,ref:n,icon:iP})};const sx=f.exports.forwardRef(aP);var lP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"}}]},name:"file",theme:"outlined"};const sP=lP;var cP=function(t,n){return C(Et,{...t,ref:n,icon:sP})};const cx=f.exports.forwardRef(cP);var uP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"}}]},name:"left",theme:"outlined"};const dP=uP;var fP=function(t,n){return C(Et,{...t,ref:n,icon:dP})};const vP=f.exports.forwardRef(fP);var pP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M574 665.4a8.03 8.03 0 00-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 00-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 000 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 000 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 00-11.3 0L372.3 598.7a8.03 8.03 0 000 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"}}]},name:"link",theme:"outlined"};const gP=pP;var hP=function(t,n){return C(Et,{...t,ref:n,icon:gP})};const mP=f.exports.forwardRef(hP);var yP={icon:{tag:"svg",attrs:{viewBox:"0 0 1024 1024",focusable:"false"},children:[{tag:"path",attrs:{d:"M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"}}]},name:"loading",theme:"outlined"};const bP=yP;var SP=function(t,n){return C(Et,{...t,ref:n,icon:bP})};const ux=f.exports.forwardRef(SP);var CP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 512a48 48 0 1096 0 48 48 0 10-96 0zm200 0a48 48 0 1096 0 48 48 0 10-96 0zm-400 0a48 48 0 1096 0 48 48 0 10-96 0zm661.2-173.6c-22.6-53.7-55-101.9-96.3-143.3a444.35 444.35 0 00-143.3-96.3C630.6 75.7 572.2 64 512 64h-2c-60.6.3-119.3 12.3-174.5 35.9a445.35 445.35 0 00-142 96.5c-40.9 41.3-73 89.3-95.2 142.8-23 55.4-34.6 114.3-34.3 174.9A449.4 449.4 0 00112 714v152a46 46 0 0046 46h152.1A449.4 449.4 0 00510 960h2.1c59.9 0 118-11.6 172.7-34.3a444.48 444.48 0 00142.8-95.2c41.3-40.9 73.8-88.7 96.5-142 23.6-55.2 35.6-113.9 35.9-174.5.3-60.9-11.5-120-34.8-175.6zm-151.1 438C704 845.8 611 884 512 884h-1.7c-60.3-.3-120.2-15.3-173.1-43.5l-8.4-4.5H188V695.2l-4.5-8.4C155.3 633.9 140.3 574 140 513.7c-.4-99.7 37.7-193.3 107.6-263.8 69.8-70.5 163.1-109.5 262.8-109.9h1.7c50 0 98.5 9.7 144.2 28.9 44.6 18.7 84.6 45.6 119 80 34.3 34.3 61.3 74.4 80 119 19.4 46.2 29.1 95.2 28.9 145.8-.6 99.6-39.7 192.9-110.1 262.7z"}}]},name:"message",theme:"outlined"};const xP=CP;var wP=function(t,n){return C(Et,{...t,ref:n,icon:xP})};const $P=f.exports.forwardRef(wP);var EP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"minus",theme:"outlined"};const MP=EP;var OP=function(t,n){return C(Et,{...t,ref:n,icon:MP})};const RP=f.exports.forwardRef(OP);var IP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M328 544h368c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8z"}},{tag:"path",attrs:{d:"M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-40 728H184V184h656v656z"}}]},name:"minus-square",theme:"outlined"};const PP=IP;var TP=function(t,n){return C(Et,{...t,ref:n,icon:PP})};const NP=f.exports.forwardRef(TP);var _P={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 632H136v-39.9l138.5-164.3 150.1 178L658.1 489 888 761.6V792zm0-129.8L664.2 396.8c-3.2-3.8-9-3.8-12.2 0L424.6 666.4l-144-170.7c-3.2-3.8-9-3.8-12.2 0L136 652.7V232h752v430.2zM304 456a88 88 0 100-176 88 88 0 000 176zm0-116c15.5 0 28 12.5 28 28s-12.5 28-28 28-28-12.5-28-28 12.5-28 28-28z"}}]},name:"picture",theme:"outlined"};const AP=_P;var DP=function(t,n){return C(Et,{...t,ref:n,icon:AP})};const LP=f.exports.forwardRef(DP);var zP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};const FP=zP;var kP=function(t,n){return C(Et,{...t,ref:n,icon:FP})};const BP=f.exports.forwardRef(kP);var jP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M328 544h152v152c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V544h152c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H544V328c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v152H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8z"}},{tag:"path",attrs:{d:"M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-40 728H184V184h656v656z"}}]},name:"plus-square",theme:"outlined"};const HP=jP;var WP=function(t,n){return C(Et,{...t,ref:n,icon:HP})};const VP=f.exports.forwardRef(WP);var UP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"};const YP=UP;var GP=function(t,n){return C(Et,{...t,ref:n,icon:YP})};const KP=f.exports.forwardRef(GP);var qP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"defs",attrs:{},children:[{tag:"style",attrs:{}}]},{tag:"path",attrs:{d:"M672 418H144c-17.7 0-32 14.3-32 32v414c0 17.7 14.3 32 32 32h528c17.7 0 32-14.3 32-32V450c0-17.7-14.3-32-32-32zm-44 402H188V494h440v326z"}},{tag:"path",attrs:{d:"M819.3 328.5c-78.8-100.7-196-153.6-314.6-154.2l-.2-64c0-6.5-7.6-10.1-12.6-6.1l-128 101c-4 3.1-3.9 9.1 0 12.3L492 318.6c5.1 4 12.7.4 12.6-6.1v-63.9c12.9.1 25.9.9 38.8 2.5 42.1 5.2 82.1 18.2 119 38.7 38.1 21.2 71.2 49.7 98.4 84.3 27.1 34.7 46.7 73.7 58.1 115.8a325.95 325.95 0 016.5 140.9h74.9c14.8-103.6-11.3-213-81-302.3z"}}]},name:"rotate-left",theme:"outlined"};const XP=qP;var QP=function(t,n){return C(Et,{...t,ref:n,icon:XP})};const ZP=f.exports.forwardRef(QP);var JP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"defs",attrs:{},children:[{tag:"style",attrs:{}}]},{tag:"path",attrs:{d:"M480.5 251.2c13-1.6 25.9-2.4 38.8-2.5v63.9c0 6.5 7.5 10.1 12.6 6.1L660 217.6c4-3.2 4-9.2 0-12.3l-128-101c-5.1-4-12.6-.4-12.6 6.1l-.2 64c-118.6.5-235.8 53.4-314.6 154.2A399.75 399.75 0 00123.5 631h74.9c-.9-5.3-1.7-10.7-2.4-16.1-5.1-42.1-2.1-84.1 8.9-124.8 11.4-42.2 31-81.1 58.1-115.8 27.2-34.7 60.3-63.2 98.4-84.3 37-20.6 76.9-33.6 119.1-38.8z"}},{tag:"path",attrs:{d:"M880 418H352c-17.7 0-32 14.3-32 32v414c0 17.7 14.3 32 32 32h528c17.7 0 32-14.3 32-32V450c0-17.7-14.3-32-32-32zm-44 402H396V494h440v326z"}}]},name:"rotate-right",theme:"outlined"};const e4=JP;var t4=function(t,n){return C(Et,{...t,ref:n,icon:e4})};const n4=f.exports.forwardRef(t4);var r4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"}}]},name:"search",theme:"outlined"};const o4=r4;var i4=function(t,n){return C(Et,{...t,ref:n,icon:o4})};const _d=f.exports.forwardRef(i4);var a4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"}}]},name:"setting",theme:"outlined"};const l4=a4;var s4=function(t,n){return C(Et,{...t,ref:n,icon:l4})};const c4=f.exports.forwardRef(s4);var u4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M288 421a48 48 0 1096 0 48 48 0 10-96 0zm352 0a48 48 0 1096 0 48 48 0 10-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 01248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 01249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 01775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 01775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 00-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 00-8-8.4z"}}]},name:"smile",theme:"outlined"};const d4=u4;var f4=function(t,n){return C(Et,{...t,ref:n,icon:d4})};const v4=f.exports.forwardRef(f4);var p4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M847.9 592H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h605.2L612.9 851c-4.1 5.2-.4 13 6.3 13h72.5c4.9 0 9.5-2.2 12.6-6.1l168.8-214.1c16.5-21 1.6-51.8-25.2-51.8zM872 356H266.8l144.3-183c4.1-5.2.4-13-6.3-13h-72.5c-4.9 0-9.5 2.2-12.6 6.1L150.9 380.2c-16.5 21-1.6 51.8 25.1 51.8h696c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"swap",theme:"outlined"};const g4=p4;var h4=function(t,n){return C(Et,{...t,ref:n,icon:g4})};const gy=f.exports.forwardRef(h4);var m4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 302.3L784 376V224c0-35.3-28.7-64-64-64H128c-35.3 0-64 28.7-64 64v576c0 35.3 28.7 64 64 64h592c35.3 0 64-28.7 64-64V648l128 73.7c21.3 12.3 48-3.1 48-27.6V330c0-24.6-26.7-40-48-27.7zM712 792H136V232h576v560zm176-167l-104-59.8V458.9L888 399v226zM208 360h112c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H208c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8z"}}]},name:"video-camera",theme:"outlined"};const y4=m4;var b4=function(t,n){return C(Et,{...t,ref:n,icon:y4})};const S4=f.exports.forwardRef(b4);var C4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M690.1 377.4c5.9 0 11.8.2 17.6.5-24.4-128.7-158.3-227.1-319.9-227.1C209 150.8 64 271.4 64 420.2c0 81.1 43.6 154.2 111.9 203.6a21.5 21.5 0 019.1 17.6c0 2.4-.5 4.6-1.1 6.9-5.5 20.3-14.2 52.8-14.6 54.3-.7 2.6-1.7 5.2-1.7 7.9 0 5.9 4.8 10.8 10.8 10.8 2.3 0 4.2-.9 6.2-2l70.9-40.9c5.3-3.1 11-5 17.2-5 3.2 0 6.4.5 9.5 1.4 33.1 9.5 68.8 14.8 105.7 14.8 6 0 11.9-.1 17.8-.4-7.1-21-10.9-43.1-10.9-66 0-135.8 132.2-245.8 295.3-245.8zm-194.3-86.5c23.8 0 43.2 19.3 43.2 43.1s-19.3 43.1-43.2 43.1c-23.8 0-43.2-19.3-43.2-43.1s19.4-43.1 43.2-43.1zm-215.9 86.2c-23.8 0-43.2-19.3-43.2-43.1s19.3-43.1 43.2-43.1 43.2 19.3 43.2 43.1-19.4 43.1-43.2 43.1zm586.8 415.6c56.9-41.2 93.2-102 93.2-169.7 0-124-120.8-224.5-269.9-224.5-149 0-269.9 100.5-269.9 224.5S540.9 847.5 690 847.5c30.8 0 60.6-4.4 88.1-12.3 2.6-.8 5.2-1.2 7.9-1.2 5.2 0 9.9 1.6 14.3 4.1l59.1 34c1.7 1 3.3 1.7 5.2 1.7a9 9 0 006.4-2.6 9 9 0 002.6-6.4c0-2.2-.9-4.4-1.4-6.6-.3-1.2-7.6-28.3-12.2-45.3-.5-1.9-.9-3.8-.9-5.7.1-5.9 3.1-11.2 7.6-14.5zM600.2 587.2c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9c0 19.8-16.2 35.9-36 35.9zm179.9 0c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9a36.08 36.08 0 01-36 35.9z"}}]},name:"wechat",theme:"outlined"};const x4=C4;var w4=function(t,n){return C(Et,{...t,ref:n,icon:x4})};const $4=f.exports.forwardRef(w4);var E4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M637 443H519V309c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v134H325c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h118v134c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V519h118c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zm284 424L775 721c122.1-148.9 113.6-369.5-26-509-148-148.1-388.4-148.1-537 0-148.1 148.6-148.1 389 0 537 139.5 139.6 360.1 148.1 509 26l146 146c3.2 2.8 8.3 2.8 11 0l43-43c2.8-2.7 2.8-7.8 0-11zM696 696c-118.8 118.7-311.2 118.7-430 0-118.7-118.8-118.7-311.2 0-430 118.8-118.7 311.2-118.7 430 0 118.7 118.8 118.7 311.2 0 430z"}}]},name:"zoom-in",theme:"outlined"};const M4=E4;var O4=function(t,n){return C(Et,{...t,ref:n,icon:M4})};const R4=f.exports.forwardRef(O4);var I4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M637 443H325c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h312c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zm284 424L775 721c122.1-148.9 113.6-369.5-26-509-148-148.1-388.4-148.1-537 0-148.1 148.6-148.1 389 0 537 139.5 139.6 360.1 148.1 509 26l146 146c3.2 2.8 8.3 2.8 11 0l43-43c2.8-2.7 2.8-7.8 0-11zM696 696c-118.8 118.7-311.2 118.7-430 0-118.7-118.8-118.7-311.2 0-430 118.8-118.7 311.2-118.7 430 0 118.7 118.8 118.7 311.2 0 430z"}}]},name:"zoom-out",theme:"outlined"};const P4=I4;var T4=function(t,n){return C(Et,{...t,ref:n,icon:P4})};const N4=f.exports.forwardRef(T4);var Kl={exports:{}},Rt={};/** + * @license React + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Dh=Symbol.for("react.element"),Lh=Symbol.for("react.portal"),Ad=Symbol.for("react.fragment"),Dd=Symbol.for("react.strict_mode"),Ld=Symbol.for("react.profiler"),zd=Symbol.for("react.provider"),Fd=Symbol.for("react.context"),_4=Symbol.for("react.server_context"),kd=Symbol.for("react.forward_ref"),Bd=Symbol.for("react.suspense"),jd=Symbol.for("react.suspense_list"),Hd=Symbol.for("react.memo"),Wd=Symbol.for("react.lazy"),A4=Symbol.for("react.offscreen"),dx;dx=Symbol.for("react.module.reference");function Cr(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case Dh:switch(e=e.type,e){case Ad:case Ld:case Dd:case Bd:case jd:return e;default:switch(e=e&&e.$$typeof,e){case _4:case Fd:case kd:case Wd:case Hd:case zd:return e;default:return t}}case Lh:return t}}}Rt.ContextConsumer=Fd;Rt.ContextProvider=zd;Rt.Element=Dh;Rt.ForwardRef=kd;Rt.Fragment=Ad;Rt.Lazy=Wd;Rt.Memo=Hd;Rt.Portal=Lh;Rt.Profiler=Ld;Rt.StrictMode=Dd;Rt.Suspense=Bd;Rt.SuspenseList=jd;Rt.isAsyncMode=function(){return!1};Rt.isConcurrentMode=function(){return!1};Rt.isContextConsumer=function(e){return Cr(e)===Fd};Rt.isContextProvider=function(e){return Cr(e)===zd};Rt.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===Dh};Rt.isForwardRef=function(e){return Cr(e)===kd};Rt.isFragment=function(e){return Cr(e)===Ad};Rt.isLazy=function(e){return Cr(e)===Wd};Rt.isMemo=function(e){return Cr(e)===Hd};Rt.isPortal=function(e){return Cr(e)===Lh};Rt.isProfiler=function(e){return Cr(e)===Ld};Rt.isStrictMode=function(e){return Cr(e)===Dd};Rt.isSuspense=function(e){return Cr(e)===Bd};Rt.isSuspenseList=function(e){return Cr(e)===jd};Rt.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===Ad||e===Ld||e===Dd||e===Bd||e===jd||e===A4||typeof e=="object"&&e!==null&&(e.$$typeof===Wd||e.$$typeof===Hd||e.$$typeof===zd||e.$$typeof===Fd||e.$$typeof===kd||e.$$typeof===dx||e.getModuleId!==void 0)};Rt.typeOf=Cr;(function(e){e.exports=Rt})(Kl);function Hs(e,t,n){var r=f.exports.useRef({});return(!("value"in r.current)||n(r.current.condition,t))&&(r.current.value=e(),r.current.condition=t),r.current.value}function zh(e,t){typeof e=="function"?e(t):Qe(e)==="object"&&e&&"current"in e&&(e.current=t)}function xr(){for(var e=arguments.length,t=new Array(e),n=0;n1&&arguments[1]!==void 0?arguments[1]:{},n=[];return lt.Children.forEach(e,function(r){r==null&&!t.keepEmpty||(Array.isArray(r)?n=n.concat(Qo(r)):Kl.exports.isFragment(r)&&r.props?n=n.concat(Qo(r.props.children,t)):n.push(r))}),n}function Wu(e){return e instanceof HTMLElement||e instanceof SVGElement}function ql(e){return Wu(e)?e:e instanceof lt.Component?zu.findDOMNode(e):null}var Lp=f.exports.createContext(null);function D4(e){var t=e.children,n=e.onBatchResize,r=f.exports.useRef(0),o=f.exports.useRef([]),i=f.exports.useContext(Lp),a=f.exports.useCallback(function(l,s,c){r.current+=1;var u=r.current;o.current.push({size:l,element:s,data:c}),Promise.resolve().then(function(){u===r.current&&(n==null||n(o.current),o.current=[])}),i==null||i(l,s,c)},[n,i]);return C(Lp.Provider,{value:a,children:t})}var fx=function(){if(typeof Map<"u")return Map;function e(t,n){var r=-1;return t.some(function(o,i){return o[0]===n?(r=i,!0):!1}),r}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(n){var r=e(this.__entries__,n),o=this.__entries__[r];return o&&o[1]},t.prototype.set=function(n,r){var o=e(this.__entries__,n);~o?this.__entries__[o][1]=r:this.__entries__.push([n,r])},t.prototype.delete=function(n){var r=this.__entries__,o=e(r,n);~o&&r.splice(o,1)},t.prototype.has=function(n){return!!~e(this.__entries__,n)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(n,r){r===void 0&&(r=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zp||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),j4?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zp||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var n=t.propertyName,r=n===void 0?"":n,o=B4.some(function(i){return!!~r.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),vx=function(e,t){for(var n=0,r=Object.keys(t);n"u"||!(Element instanceof Object))){if(!(t instanceof Ua(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var n=this.observations_;n.has(t)||(n.set(t,new X4(t)),this.controller_.addObserver(this),this.controller_.refresh())}},e.prototype.unobserve=function(t){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");if(!(typeof Element>"u"||!(Element instanceof Object))){if(!(t instanceof Ua(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var n=this.observations_;!n.has(t)||(n.delete(t),n.size||this.controller_.removeObserver(this))}},e.prototype.disconnect=function(){this.clearActive(),this.observations_.clear(),this.controller_.removeObserver(this)},e.prototype.gatherActive=function(){var t=this;this.clearActive(),this.observations_.forEach(function(n){n.isActive()&&t.activeObservations_.push(n)})},e.prototype.broadcastActive=function(){if(!!this.hasActive()){var t=this.callbackCtx_,n=this.activeObservations_.map(function(r){return new Q4(r.target,r.broadcastRect())});this.callback_.call(t,n,t),this.clearActive()}},e.prototype.clearActive=function(){this.activeObservations_.splice(0)},e.prototype.hasActive=function(){return this.activeObservations_.length>0},e}(),gx=typeof WeakMap<"u"?new WeakMap:new fx,hx=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var n=H4.getInstance(),r=new Z4(t,n,this);gx.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){hx.prototype[e]=function(){var t;return(t=gx.get(this))[e].apply(t,arguments)}});var J4=function(){return typeof Vu.ResizeObserver<"u"?Vu.ResizeObserver:hx}(),Lo=new Map;function eT(e){e.forEach(function(t){var n,r=t.target;(n=Lo.get(r))===null||n===void 0||n.forEach(function(o){return o(r)})})}var mx=new J4(eT);function tT(e,t){Lo.has(e)||(Lo.set(e,new Set),mx.observe(e)),Lo.get(e).add(t)}function nT(e,t){Lo.has(e)&&(Lo.get(e).delete(t),Lo.get(e).size||(mx.unobserve(e),Lo.delete(e)))}function zn(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function my(e,t){for(var n=0;n1&&arguments[1]!==void 0?arguments[1]:1;yy+=1;var r=yy;function o(i){if(i===0)Cx(r),t();else{var a=bx(function(){o(i-1)});kh.set(r,a)}}return o(n),r};St.cancel=function(e){var t=kh.get(e);return Cx(e),Sx(t)};function Yu(e){for(var t=0,n,r=0,o=e.length;o>=4;++r,o-=4)n=e.charCodeAt(r)&255|(e.charCodeAt(++r)&255)<<8|(e.charCodeAt(++r)&255)<<16|(e.charCodeAt(++r)&255)<<24,n=(n&65535)*1540483477+((n>>>16)*59797<<16),n^=n>>>24,t=(n&65535)*1540483477+((n>>>16)*59797<<16)^(t&65535)*1540483477+((t>>>16)*59797<<16);switch(o){case 3:t^=(e.charCodeAt(r+2)&255)<<16;case 2:t^=(e.charCodeAt(r+1)&255)<<8;case 1:t^=e.charCodeAt(r)&255,t=(t&65535)*1540483477+((t>>>16)*59797<<16)}return t^=t>>>13,t=(t&65535)*1540483477+((t>>>16)*59797<<16),((t^t>>>15)>>>0).toString(36)}function Vs(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1,r=new Set;function o(i,a){var l=arguments.length>2&&arguments[2]!==void 0?arguments[2]:1,s=r.has(i);if(Mn(!s,"Warning: There may be circular references"),s)return!1;if(i===a)return!0;if(n&&l>1)return!1;r.add(i);var c=l+1;if(Array.isArray(i)){if(!Array.isArray(a)||i.length!==a.length)return!1;for(var u=0;u1&&arguments[1]!==void 0?arguments[1]:!1,a={map:this.cache};return n.forEach(function(l){if(!a)a=void 0;else{var s;a=(s=a)===null||s===void 0||(s=s.map)===null||s===void 0?void 0:s.get(l)}}),(r=a)!==null&&r!==void 0&&r.value&&i&&(a.value[1]=this.cacheCallTimes++),(o=a)===null||o===void 0?void 0:o.value}},{key:"get",value:function(n){var r;return(r=this.internalGet(n,!0))===null||r===void 0?void 0:r[0]}},{key:"has",value:function(n){return!!this.internalGet(n)}},{key:"set",value:function(n,r){var o=this;if(!this.has(n)){if(this.size()+1>e.MAX_CACHE_SIZE+e.MAX_CACHE_OFFSET){var i=this.keys.reduce(function(c,u){var d=G(c,2),v=d[1];return o.internalGet(u)[1]0,void 0),by+=1}return Fn(e,[{key:"getDerivativeToken",value:function(n){return this.derivatives.reduce(function(r,o){return o(n,r)},void 0)}}]),e}(),Jf=new Bh;function Bp(e){var t=Array.isArray(e)?e:[e];return Jf.has(t)||Jf.set(t,new xx(t)),Jf.get(t)}var pT=new WeakMap,ev={};function gT(e,t){for(var n=pT,r=0;r3&&arguments[3]!==void 0?arguments[3]:{},i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1;if(i)return e;var a=U(U({},o),{},(r={},V(r,Ya,t),V(r,zr,n),r)),l=Object.keys(a).map(function(s){var c=a[s];return c?"".concat(s,'="').concat(c,'"'):null}).filter(function(s){return s}).join(" ");return"")}var $x=function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"";return"--".concat(n?"".concat(n,"-"):"").concat(t).replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z0-9]+)/g,"$1-$2").replace(/([a-z])([A-Z0-9])/g,"$1-$2").toLowerCase()},yT=function(t,n,r){return Object.keys(t).length?".".concat(n).concat(r!=null&&r.scope?".".concat(r.scope):"","{").concat(Object.entries(t).map(function(o){var i=G(o,2),a=i[0],l=i[1];return"".concat(a,":").concat(l,";")}).join(""),"}"):""},Ex=function(t,n,r){var o={},i={};return Object.entries(t).forEach(function(a){var l,s,c=G(a,2),u=c[0],d=c[1];if(r!=null&&(l=r.preserve)!==null&&l!==void 0&&l[u])i[u]=d;else if((typeof d=="string"||typeof d=="number")&&!(r!=null&&(s=r.ignore)!==null&&s!==void 0&&s[u])){var v,h=$x(u,r==null?void 0:r.prefix);o[h]=typeof d=="number"&&!(r!=null&&(v=r.unitless)!==null&&v!==void 0&&v[u])?"".concat(d,"px"):String(d),i[u]="var(".concat(h,")")}}),[i,yT(o,n,{scope:r==null?void 0:r.scope})]},xy=Rn()?f.exports.useLayoutEffect:f.exports.useEffect,Nt=function(t,n){var r=f.exports.useRef(!0);xy(function(){return t(r.current)},n),xy(function(){return r.current=!1,function(){r.current=!0}},[])},Hp=function(t,n){Nt(function(r){if(!r)return t()},n)},bT=U({},As),wy=bT.useInsertionEffect,ST=function(t,n,r){f.exports.useMemo(t,r),Nt(function(){return n(!0)},r)},CT=wy?function(e,t,n){return wy(function(){return e(),t()},n)}:ST,xT=U({},As),wT=xT.useInsertionEffect,$T=function(t){var n=[],r=!1;function o(i){r||n.push(i)}return f.exports.useEffect(function(){return r=!1,function(){r=!0,n.length&&n.forEach(function(i){return i()})}},t),o},ET=function(){return function(t){t()}},MT=typeof wT<"u"?$T:ET;function jh(e,t,n,r,o){var i=f.exports.useContext(Yd),a=i.cache,l=[e].concat(Oe(t)),s=kp(l),c=MT([s]),u=function(g){a.opUpdate(s,function(p){var b=p||[void 0,void 0],m=G(b,2),y=m[0],S=y===void 0?0:y,x=m[1],$=x,E=$||n(),w=[S,E];return g?g(w):w})};f.exports.useMemo(function(){u()},[s]);var d=a.opGet(s),v=d[1];return CT(function(){o==null||o(v)},function(h){return u(function(g){var p=G(g,2),b=p[0],m=p[1];return h&&b===0&&(o==null||o(v)),[b+1,m]}),function(){a.opUpdate(s,function(g){var p=g||[],b=G(p,2),m=b[0],y=m===void 0?0:m,S=b[1],x=y-1;return x===0?(c(function(){(h||!a.opGet(s))&&(r==null||r(S,!1))}),null):[y-1,S]})}},[s]),v}var OT={},RT="css",gi=new Map;function IT(e){gi.set(e,(gi.get(e)||0)+1)}function PT(e,t){if(typeof document<"u"){var n=document.querySelectorAll("style[".concat(Ya,'="').concat(e,'"]'));n.forEach(function(r){if(r[zo]===t){var o;(o=r.parentNode)===null||o===void 0||o.removeChild(r)}})}}var TT=0;function NT(e,t){gi.set(e,(gi.get(e)||0)-1);var n=Array.from(gi.keys()),r=n.filter(function(o){var i=gi.get(o)||0;return i<=0});n.length-r.length>TT&&r.forEach(function(o){PT(o,t),gi.delete(o)})}var _T=function(t,n,r,o){var i=r.getDerivativeToken(t),a=U(U({},i),n);return o&&(a=o(a)),a},Mx="token";function AT(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=f.exports.useContext(Yd),o=r.cache.instanceId,i=r.container,a=n.salt,l=a===void 0?"":a,s=n.override,c=s===void 0?OT:s,u=n.formatToken,d=n.getComputedToken,v=n.cssVar,h=gT(function(){return Object.assign.apply(Object,[{}].concat(Oe(t)))},t),g=Xl(h),p=Xl(c),b=v?Xl(v):"",m=jh(Mx,[l,e.id,g,p,b],function(){var y,S=d?d(h,c,e):_T(h,c,e,u),x=U({},S),$="";if(v){var E=Ex(S,v.key,{prefix:v.prefix,ignore:v.ignore,unitless:v.unitless,preserve:v.preserve}),w=G(E,2);S=w[0],$=w[1]}var R=Cy(S,l);S._tokenKey=R,x._tokenKey=Cy(x,l);var P=(y=v==null?void 0:v.key)!==null&&y!==void 0?y:R;S._themeKey=P,IT(P);var N="".concat(RT,"-").concat(Yu(R));return S._hashId=N,[S,N,x,$,(v==null?void 0:v.key)||""]},function(y){NT(y[0]._themeKey,o)},function(y){var S=G(y,4),x=S[0],$=S[3];if(v&&$){var E=Xo($,Yu("css-variables-".concat(x._themeKey)),{mark:zr,prepend:"queue",attachTo:i,priority:-999});E[zo]=o,E.setAttribute(Ya,x._themeKey)}});return m}var DT=function(t,n,r){var o=G(t,5),i=o[2],a=o[3],l=o[4],s=r||{},c=s.plain;if(!a)return null;var u=i._tokenKey,d=-999,v={"data-rc-order":"prependQueue","data-rc-priority":"".concat(d)},h=Gu(a,l,u,v,c);return[d,u,h]},LT={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},Ox="comm",Rx="rule",Ix="decl",zT="@import",FT="@keyframes",kT="@layer",Px=Math.abs,Hh=String.fromCharCode;function Tx(e){return e.trim()}function eu(e,t,n){return e.replace(t,n)}function BT(e,t,n){return e.indexOf(t,n)}function Cs(e,t){return e.charCodeAt(t)|0}function xs(e,t,n){return e.slice(t,n)}function so(e){return e.length}function jT(e){return e.length}function Mc(e,t){return t.push(e),e}var Gd=1,Ga=1,Nx=0,Sr=0,en=0,nl="";function Wh(e,t,n,r,o,i,a,l){return{value:e,root:t,parent:n,type:r,props:o,children:i,line:Gd,column:Ga,length:a,return:"",siblings:l}}function HT(){return en}function WT(){return en=Sr>0?Cs(nl,--Sr):0,Ga--,en===10&&(Ga=1,Gd--),en}function Fr(){return en=Sr2||Wp(en)>3?"":" "}function GT(e,t){for(;--t&&Fr()&&!(en<48||en>102||en>57&&en<65||en>70&&en<97););return Kd(e,tu()+(t<6&&Mi()==32&&Fr()==32))}function Vp(e){for(;Fr();)switch(en){case e:return Sr;case 34:case 39:e!==34&&e!==39&&Vp(en);break;case 40:e===41&&Vp(e);break;case 92:Fr();break}return Sr}function KT(e,t){for(;Fr()&&e+en!==47+10;)if(e+en===42+42&&Mi()===47)break;return"/*"+Kd(t,Sr-1)+"*"+Hh(e===47?e:Fr())}function qT(e){for(;!Wp(Mi());)Fr();return Kd(e,Sr)}function XT(e){return UT(nu("",null,null,null,[""],e=VT(e),0,[0],e))}function nu(e,t,n,r,o,i,a,l,s){for(var c=0,u=0,d=a,v=0,h=0,g=0,p=1,b=1,m=1,y=0,S="",x=o,$=i,E=r,w=S;b;)switch(g=y,y=Fr()){case 40:if(g!=108&&Cs(w,d-1)==58){BT(w+=eu(nv(y),"&","&\f"),"&\f",Px(c?l[c-1]:0))!=-1&&(m=-1);break}case 34:case 39:case 91:w+=nv(y);break;case 9:case 10:case 13:case 32:w+=YT(g);break;case 92:w+=GT(tu()-1,7);continue;case 47:switch(Mi()){case 42:case 47:Mc(QT(KT(Fr(),tu()),t,n,s),s);break;default:w+="/"}break;case 123*p:l[c++]=so(w)*m;case 125*p:case 59:case 0:switch(y){case 0:case 125:b=0;case 59+u:m==-1&&(w=eu(w,/\f/g,"")),h>0&&so(w)-d&&Mc(h>32?Ey(w+";",r,n,d-1,s):Ey(eu(w," ","")+";",r,n,d-2,s),s);break;case 59:w+=";";default:if(Mc(E=$y(w,t,n,c,u,o,l,S,x=[],$=[],d,i),i),y===123)if(u===0)nu(w,t,E,E,x,i,d,l,$);else switch(v===99&&Cs(w,3)===110?100:v){case 100:case 108:case 109:case 115:nu(e,E,E,r&&Mc($y(e,E,E,0,0,o,l,S,o,x=[],d,$),$),o,$,d,l,r?x:$);break;default:nu(w,E,E,E,[""],$,0,l,$)}}c=u=h=0,p=m=1,S=w="",d=a;break;case 58:d=1+so(w),h=g;default:if(p<1){if(y==123)--p;else if(y==125&&p++==0&&WT()==125)continue}switch(w+=Hh(y),y*p){case 38:m=u>0?1:(w+="\f",-1);break;case 44:l[c++]=(so(w)-1)*m,m=1;break;case 64:Mi()===45&&(w+=nv(Fr())),v=Mi(),u=d=so(S=w+=qT(tu())),y++;break;case 45:g===45&&so(w)==2&&(p=0)}}return i}function $y(e,t,n,r,o,i,a,l,s,c,u,d){for(var v=o-1,h=o===0?i:[""],g=jT(h),p=0,b=0,m=0;p0?h[y]+" "+S:eu(S,/&\f/g,h[y])))&&(s[m++]=x);return Wh(e,t,n,o===0?Rx:l,s,c,u,d)}function QT(e,t,n,r){return Wh(e,t,n,Ox,Hh(HT()),xs(e,2,-2),0,r)}function Ey(e,t,n,r,o){return Wh(e,t,n,Ix,xs(e,0,r),xs(e,r+1,-1),r,o)}function Up(e,t){for(var n="",r=0;r1&&arguments[1]!==void 0?arguments[1]:{},r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{root:!0,parentSelectors:[]},o=r.root,i=r.injectHash,a=r.parentSelectors,l=n.hashId,s=n.layer;n.path;var c=n.hashPriority,u=n.transformers,d=u===void 0?[]:u;n.linters;var v="",h={};function g(S){var x=S.getName(l);if(!h[x]){var $=e(S.style,n,{root:!1,parentSelectors:a}),E=G($,1),w=E[0];h[x]="@keyframes ".concat(S.getName(l)).concat(w)}}function p(S){var x=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[];return S.forEach(function($){Array.isArray($)?p($,x):$&&x.push($)}),x}var b=p(Array.isArray(t)?t:[t]);if(b.forEach(function(S){var x=typeof S=="string"&&!o?{}:S;if(typeof x=="string")v+="".concat(x,` +`);else if(x._keyframe)g(x);else{var $=d.reduce(function(E,w){var R;return(w==null||(R=w.visit)===null||R===void 0?void 0:R.call(w,E))||E},x);Object.keys($).forEach(function(E){var w=$[E];if(Qe(w)==="object"&&w&&(E!=="animationName"||!w._keyframe)&&!r3(w)){var R=!1,P=E.trim(),N=!1;(o||i)&&l?P.startsWith("@")?R=!0:P=o3(E,l,c):o&&!l&&(P==="&"||P==="")&&(P="",N=!0);var I=e(w,n,{root:N,injectHash:R,parentSelectors:[].concat(Oe(a),[P])}),z=G(I,2),F=z[0],T=z[1];h=U(U({},h),T),v+="".concat(P).concat(F)}else{let M=function(L,A){var B=L.replace(/[A-Z]/g,function(j){return"-".concat(j.toLowerCase())}),k=A;!LT[L]&&typeof k=="number"&&k!==0&&(k="".concat(k,"px")),L==="animationName"&&A!==null&&A!==void 0&&A._keyframe&&(g(A),k=A.getName(l)),v+="".concat(B,":").concat(k,";")};var O=M,D,_=(D=w==null?void 0:w.value)!==null&&D!==void 0?D:w;Qe(w)==="object"&&w!==null&&w!==void 0&&w[Dx]&&Array.isArray(_)?_.forEach(function(L){M(E,L)}):M(E,_)}})}}),!o)v="{".concat(v,"}");else if(s&&mT()){var m=s.split(","),y=m[m.length-1].trim();v="@layer ".concat(y," {").concat(v,"}"),m.length>1&&(v="@layer ".concat(s,"{%%%:%}").concat(v))}return[v,h]};function Lx(e,t){return Yu("".concat(e.join("%")).concat(t))}function a3(){return null}var zx="style";function Gp(e,t){var n=e.token,r=e.path,o=e.hashId,i=e.layer,a=e.nonce,l=e.clientOnly,s=e.order,c=s===void 0?0:s,u=f.exports.useContext(Yd),d=u.autoClear;u.mock;var v=u.defaultCache,h=u.hashPriority,g=u.container,p=u.ssrInline,b=u.transformers,m=u.linters,y=u.cache,S=n._tokenKey,x=[S].concat(Oe(r)),$=jp,E=jh(zx,x,function(){var I=x.join("|");if(e3(I)){var z=t3(I),F=G(z,2),T=F[0],D=F[1];if(T)return[T,S,D,{},l,c]}var _=t(),O=i3(_,{hashId:o,hashPriority:h,layer:i,path:r.join("-"),transformers:b,linters:m}),M=G(O,2),L=M[0],A=M[1],B=Yp(L),k=Lx(x,B);return[B,S,k,A,l,c]},function(I,z){var F=G(I,3),T=F[2];(z||d)&&jp&&Ss(T,{mark:zr})},function(I){var z=G(I,4),F=z[0];z[1];var T=z[2],D=z[3];if($&&F!==_x){var _={mark:zr,prepend:"queue",attachTo:g,priority:c},O=typeof a=="function"?a():a;O&&(_.csp={nonce:O});var M=Xo(F,T,_);M[zo]=y.instanceId,M.setAttribute(Ya,S),Object.keys(D).forEach(function(L){Xo(Yp(D[L]),"_effect-".concat(L),_)})}}),w=G(E,3),R=w[0],P=w[1],N=w[2];return function(I){var z;if(!p||$||!v)z=C(a3,{});else{var F;z=C("style",{...(F={},V(F,Ya,P),V(F,zr,N),F),dangerouslySetInnerHTML:{__html:R}})}return ie(Tt,{children:[z,I]})}}var l3=function(t,n,r){var o=G(t,6),i=o[0],a=o[1],l=o[2],s=o[3],c=o[4],u=o[5],d=r||{},v=d.plain;if(c)return null;var h=i,g={"data-rc-order":"prependQueue","data-rc-priority":"".concat(u)};return h=Gu(i,a,l,g,v),s&&Object.keys(s).forEach(function(p){if(!n[p]){n[p]=!0;var b=Yp(s[p]);h+=Gu(b,a,"_effect-".concat(p),g,v)}}),[u,l,h]},Fx="cssVar",s3=function(t,n){var r=t.key,o=t.prefix,i=t.unitless,a=t.ignore,l=t.token,s=t.scope,c=s===void 0?"":s,u=f.exports.useContext(Yd),d=u.cache.instanceId,v=u.container,h=l._tokenKey,g=[].concat(Oe(t.path),[r,c,h]),p=jh(Fx,g,function(){var b=n(),m=Ex(b,r,{prefix:o,unitless:i,ignore:a,scope:c}),y=G(m,2),S=y[0],x=y[1],$=Lx(g,x);return[S,x,$,r]},function(b){var m=G(b,3),y=m[2];jp&&Ss(y,{mark:zr})},function(b){var m=G(b,3),y=m[1],S=m[2];if(!!y){var x=Xo(y,S,{mark:zr,prepend:"queue",attachTo:v,priority:-999});x[zo]=d,x.setAttribute(Ya,r)}});return p},c3=function(t,n,r){var o=G(t,4),i=o[1],a=o[2],l=o[3],s=r||{},c=s.plain;if(!i)return null;var u=-999,d={"data-rc-order":"prependQueue","data-rc-priority":"".concat(u)},v=Gu(i,l,a,d,c);return[u,a,v]},bl;bl={},V(bl,zx,l3),V(bl,Mx,DT),V(bl,Fx,c3);var Ct=function(){function e(t,n){zn(this,e),V(this,"name",void 0),V(this,"style",void 0),V(this,"_keyframe",!0),this.name=t,this.style=n}return Fn(e,[{key:"getName",value:function(){var n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"";return n?"".concat(n,"-").concat(this.name):this.name}}]),e}();function Yi(e){return e.notSplit=!0,e}Yi(["borderTop","borderBottom"]),Yi(["borderTop"]),Yi(["borderBottom"]),Yi(["borderLeft","borderRight"]),Yi(["borderLeft"]),Yi(["borderRight"]);function kx(e){return VC(e)||yx(e)||Nh(e)||UC()}function qr(e,t){for(var n=e,r=0;r3&&arguments[3]!==void 0?arguments[3]:!1;return t.length&&r&&n===void 0&&!qr(e,t.slice(0,-1))?e:Bx(e,t,n,r)}function u3(e){return Qe(e)==="object"&&e!==null&&Object.getPrototypeOf(e)===Object.prototype}function Oy(e){return Array.isArray(e)?[]:{}}var d3=typeof Reflect>"u"?Object.keys:Reflect.ownKeys;function Ca(){for(var e=arguments.length,t=new Array(e),n=0;n{const e=()=>{};return e.deprecated=f3,e},p3=f.exports.createContext(void 0);var g3={items_per_page:"/ page",jump_to:"Go to",jump_to_confirm:"confirm",page:"Page",prev_page:"Previous Page",next_page:"Next Page",prev_5:"Previous 5 Pages",next_5:"Next 5 Pages",prev_3:"Previous 3 Pages",next_3:"Next 3 Pages",page_size:"Page Size"},h3={locale:"en_US",today:"Today",now:"Now",backToToday:"Back to today",ok:"OK",clear:"Clear",month:"Month",year:"Year",timeSelect:"select time",dateSelect:"select date",weekSelect:"Choose a week",monthSelect:"Choose a month",yearSelect:"Choose a year",decadeSelect:"Choose a decade",yearFormat:"YYYY",dateFormat:"M/D/YYYY",dayFormat:"D",dateTimeFormat:"M/D/YYYY HH:mm:ss",monthBeforeYear:!0,previousMonth:"Previous month (PageUp)",nextMonth:"Next month (PageDown)",previousYear:"Last year (Control + left)",nextYear:"Next year (Control + right)",previousDecade:"Last decade",nextDecade:"Next decade",previousCentury:"Last century",nextCentury:"Next century"};const m3={placeholder:"Select time",rangePlaceholder:["Start time","End time"]},Hx=m3,y3={lang:Object.assign({placeholder:"Select date",yearPlaceholder:"Select year",quarterPlaceholder:"Select quarter",monthPlaceholder:"Select month",weekPlaceholder:"Select week",rangePlaceholder:["Start date","End date"],rangeYearPlaceholder:["Start year","End year"],rangeQuarterPlaceholder:["Start quarter","End quarter"],rangeMonthPlaceholder:["Start month","End month"],rangeWeekPlaceholder:["Start week","End week"]},h3),timePickerLocale:Object.assign({},Hx)},Kp=y3,Qn="${label} is not a valid ${type}",b3={locale:"en",Pagination:g3,DatePicker:Kp,TimePicker:Hx,Calendar:Kp,global:{placeholder:"Please select"},Table:{filterTitle:"Filter menu",filterConfirm:"OK",filterReset:"Reset",filterEmptyText:"No filters",filterCheckall:"Select all items",filterSearchPlaceholder:"Search in filters",emptyText:"No data",selectAll:"Select current page",selectInvert:"Invert current page",selectNone:"Clear all data",selectionAll:"Select all data",sortTitle:"Sort",expand:"Expand row",collapse:"Collapse row",triggerDesc:"Click to sort descending",triggerAsc:"Click to sort ascending",cancelSort:"Click to cancel sorting"},Tour:{Next:"Next",Previous:"Previous",Finish:"Finish"},Modal:{okText:"OK",cancelText:"Cancel",justOkText:"OK"},Popconfirm:{okText:"OK",cancelText:"Cancel"},Transfer:{titles:["",""],searchPlaceholder:"Search here",itemUnit:"item",itemsUnit:"items",remove:"Remove",selectCurrent:"Select current page",removeCurrent:"Remove current page",selectAll:"Select all data",removeAll:"Remove all data",selectInvert:"Invert current page"},Upload:{uploading:"Uploading...",removeFile:"Remove file",uploadError:"Upload error",previewFile:"Preview file",downloadFile:"Download file"},Empty:{description:"No data"},Icon:{icon:"icon"},Text:{edit:"Edit",copy:"Copy",copied:"Copied",expand:"Expand"},Form:{optional:"(optional)",defaultValidateMessages:{default:"Field validation error for ${label}",required:"Please enter ${label}",enum:"${label} must be one of [${enum}]",whitespace:"${label} cannot be a blank character",date:{format:"${label} date format is invalid",parse:"${label} cannot be converted to a date",invalid:"${label} is an invalid date"},types:{string:Qn,method:Qn,array:Qn,object:Qn,number:Qn,date:Qn,boolean:Qn,integer:Qn,float:Qn,regexp:Qn,email:Qn,url:Qn,hex:Qn},string:{len:"${label} must be ${len} characters",min:"${label} must be at least ${min} characters",max:"${label} must be up to ${max} characters",range:"${label} must be between ${min}-${max} characters"},number:{len:"${label} must be equal to ${len}",min:"${label} must be minimum ${min}",max:"${label} must be maximum ${max}",range:"${label} must be between ${min}-${max}"},array:{len:"Must be ${len} ${label}",min:"At least ${min} ${label}",max:"At most ${max} ${label}",range:"The amount of ${label} must be between ${min}-${max}"},pattern:{mismatch:"${label} does not match the pattern ${pattern}"}}},Image:{preview:"Preview"},QRCode:{expired:"QR code expired",refresh:"Refresh",scanned:"Scanned"},ColorPicker:{presetEmpty:"Empty"}},Jo=b3;Object.assign({},Jo.Modal);let ru=[];const Ry=()=>ru.reduce((e,t)=>Object.assign(Object.assign({},e),t),Jo.Modal);function S3(e){if(e){const t=Object.assign({},e);return ru.push(t),Ry(),()=>{ru=ru.filter(n=>n!==t),Ry()}}Object.assign({},Jo.Modal)}const C3=f.exports.createContext(void 0),Vh=C3,x3=(e,t)=>{const n=f.exports.useContext(Vh),r=f.exports.useMemo(()=>{var i;const a=t||Jo[e],l=(i=n==null?void 0:n[e])!==null&&i!==void 0?i:{};return Object.assign(Object.assign({},typeof a=="function"?a():a),l||{})},[e,t,n]),o=f.exports.useMemo(()=>{const i=n==null?void 0:n.locale;return(n==null?void 0:n.exist)&&!i?Jo.locale:i},[n]);return[r,o]},Wx=x3,w3="internalMark",$3=e=>{const{locale:t={},children:n,_ANT_MARK__:r}=e;f.exports.useEffect(()=>S3(t&&t.Modal),[t]);const o=f.exports.useMemo(()=>Object.assign(Object.assign({},t),{exist:!0}),[t]);return C(Vh.Provider,{value:o,children:n})},E3=$3,M3=e=>{const{controlHeight:t}=e;return{controlHeightSM:t*.75,controlHeightXS:t*.5,controlHeightLG:t*1.25}},O3=M3;function R3(e){const{sizeUnit:t,sizeStep:n}=e;return{sizeXXL:t*(n+8),sizeXL:t*(n+4),sizeLG:t*(n+2),sizeMD:t*(n+1),sizeMS:t*n,size:t*n,sizeSM:t*(n-1),sizeXS:t*(n-2),sizeXXS:t*(n-3)}}const Vx={blue:"#1677ff",purple:"#722ED1",cyan:"#13C2C2",green:"#52C41A",magenta:"#EB2F96",pink:"#eb2f96",red:"#F5222D",orange:"#FA8C16",yellow:"#FADB14",volcano:"#FA541C",geekblue:"#2F54EB",gold:"#FAAD14",lime:"#A0D911"},I3=Object.assign(Object.assign({},Vx),{colorPrimary:"#1677ff",colorSuccess:"#52c41a",colorWarning:"#faad14",colorError:"#ff4d4f",colorInfo:"#1677ff",colorLink:"",colorTextBase:"",colorBgBase:"",fontFamily:`-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, +'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', +'Noto Color Emoji'`,fontFamilyCode:"'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace",fontSize:14,lineWidth:1,lineType:"solid",motionUnit:.1,motionBase:0,motionEaseOutCirc:"cubic-bezier(0.08, 0.82, 0.17, 1)",motionEaseInOutCirc:"cubic-bezier(0.78, 0.14, 0.15, 0.86)",motionEaseOut:"cubic-bezier(0.215, 0.61, 0.355, 1)",motionEaseInOut:"cubic-bezier(0.645, 0.045, 0.355, 1)",motionEaseOutBack:"cubic-bezier(0.12, 0.4, 0.29, 1.46)",motionEaseInBack:"cubic-bezier(0.71, -0.46, 0.88, 0.6)",motionEaseInQuint:"cubic-bezier(0.755, 0.05, 0.855, 0.06)",motionEaseOutQuint:"cubic-bezier(0.23, 1, 0.32, 1)",borderRadius:6,sizeUnit:4,sizeStep:4,sizePopupArrow:16,controlHeight:32,zIndexBase:0,zIndexPopupBase:1e3,opacityImage:1,wireframe:!1,motion:!0}),ws=I3;function P3(e,t){let{generateColorPalettes:n,generateNeutralColorPalettes:r}=t;const{colorSuccess:o,colorWarning:i,colorError:a,colorInfo:l,colorPrimary:s,colorBgBase:c,colorTextBase:u}=e,d=n(s),v=n(o),h=n(i),g=n(a),p=n(l),b=r(c,u),m=e.colorLink||e.colorInfo,y=n(m);return Object.assign(Object.assign({},b),{colorPrimaryBg:d[1],colorPrimaryBgHover:d[2],colorPrimaryBorder:d[3],colorPrimaryBorderHover:d[4],colorPrimaryHover:d[5],colorPrimary:d[6],colorPrimaryActive:d[7],colorPrimaryTextHover:d[8],colorPrimaryText:d[9],colorPrimaryTextActive:d[10],colorSuccessBg:v[1],colorSuccessBgHover:v[2],colorSuccessBorder:v[3],colorSuccessBorderHover:v[4],colorSuccessHover:v[4],colorSuccess:v[6],colorSuccessActive:v[7],colorSuccessTextHover:v[8],colorSuccessText:v[9],colorSuccessTextActive:v[10],colorErrorBg:g[1],colorErrorBgHover:g[2],colorErrorBorder:g[3],colorErrorBorderHover:g[4],colorErrorHover:g[5],colorError:g[6],colorErrorActive:g[7],colorErrorTextHover:g[8],colorErrorText:g[9],colorErrorTextActive:g[10],colorWarningBg:h[1],colorWarningBgHover:h[2],colorWarningBorder:h[3],colorWarningBorderHover:h[4],colorWarningHover:h[4],colorWarning:h[6],colorWarningActive:h[7],colorWarningTextHover:h[8],colorWarningText:h[9],colorWarningTextActive:h[10],colorInfoBg:p[1],colorInfoBgHover:p[2],colorInfoBorder:p[3],colorInfoBorderHover:p[4],colorInfoHover:p[4],colorInfo:p[6],colorInfoActive:p[7],colorInfoTextHover:p[8],colorInfoText:p[9],colorInfoTextActive:p[10],colorLinkHover:y[4],colorLink:y[6],colorLinkActive:y[7],colorBgMask:new Mt("#000").setAlpha(.45).toRgbString(),colorWhite:"#fff"})}const T3=e=>{let t=e,n=e,r=e,o=e;return e<6&&e>=5?t=e+1:e<16&&e>=6?t=e+2:e>=16&&(t=16),e<7&&e>=5?n=4:e<8&&e>=7?n=5:e<14&&e>=8?n=6:e<16&&e>=14?n=7:e>=16&&(n=8),e<6&&e>=2?r=1:e>=6&&(r=2),e>4&&e<8?o=4:e>=8&&(o=6),{borderRadius:e,borderRadiusXS:r,borderRadiusSM:n,borderRadiusLG:t,borderRadiusOuter:o}},N3=T3;function _3(e){const{motionUnit:t,motionBase:n,borderRadius:r,lineWidth:o}=e;return Object.assign({motionDurationFast:`${(n+t).toFixed(1)}s`,motionDurationMid:`${(n+t*2).toFixed(1)}s`,motionDurationSlow:`${(n+t*3).toFixed(1)}s`,lineWidthBold:o+1},N3(r))}const io=(e,t)=>new Mt(e).setAlpha(t).toRgbString(),Sl=(e,t)=>new Mt(e).darken(t).toHexString(),A3=e=>{const t=Ai(e);return{1:t[0],2:t[1],3:t[2],4:t[3],5:t[4],6:t[5],7:t[6],8:t[4],9:t[5],10:t[6]}},D3=(e,t)=>{const n=e||"#fff",r=t||"#000";return{colorBgBase:n,colorTextBase:r,colorText:io(r,.88),colorTextSecondary:io(r,.65),colorTextTertiary:io(r,.45),colorTextQuaternary:io(r,.25),colorFill:io(r,.15),colorFillSecondary:io(r,.06),colorFillTertiary:io(r,.04),colorFillQuaternary:io(r,.02),colorBgLayout:Sl(n,4),colorBgContainer:Sl(n,0),colorBgElevated:Sl(n,0),colorBgSpotlight:io(r,.85),colorBgBlur:"transparent",colorBorder:Sl(n,15),colorBorderSecondary:Sl(n,6)}};function ou(e){return(e+8)/e}function L3(e){const t=new Array(10).fill(null).map((n,r)=>{const o=r-1,i=e*Math.pow(2.71828,o/5),a=r>1?Math.floor(i):Math.ceil(i);return Math.floor(a/2)*2});return t[1]=e,t.map(n=>({size:n,lineHeight:ou(n)}))}const z3=e=>{const t=L3(e),n=t.map(u=>u.size),r=t.map(u=>u.lineHeight),o=n[1],i=n[0],a=n[2],l=r[1],s=r[0],c=r[2];return{fontSizeSM:i,fontSize:o,fontSizeLG:a,fontSizeXL:n[3],fontSizeHeading1:n[6],fontSizeHeading2:n[5],fontSizeHeading3:n[4],fontSizeHeading4:n[3],fontSizeHeading5:n[2],lineHeight:l,lineHeightLG:c,lineHeightSM:s,fontHeight:Math.round(l*o),fontHeightLG:Math.round(c*a),fontHeightSM:Math.round(s*i),lineHeightHeading1:r[6],lineHeightHeading2:r[5],lineHeightHeading3:r[4],lineHeightHeading4:r[3],lineHeightHeading5:r[2]}},F3=z3;function k3(e){const t=Object.keys(Vx).map(n=>{const r=Ai(e[n]);return new Array(10).fill(1).reduce((o,i,a)=>(o[`${n}-${a+1}`]=r[a],o[`${n}${a+1}`]=r[a],o),{})}).reduce((n,r)=>(n=Object.assign(Object.assign({},n),r),n),{});return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},e),t),P3(e,{generateColorPalettes:A3,generateNeutralColorPalettes:D3})),F3(e.fontSize)),R3(e)),O3(e)),_3(e))}const Ux=Bp(k3),qp={token:ws,override:{override:ws},hashed:!0},Yx=lt.createContext(qp),Gx="anticon",B3=(e,t)=>t||(e?`ant-${e}`:"ant"),ot=f.exports.createContext({getPrefixCls:B3,iconPrefixCls:Gx}),j3=`-ant-${Date.now()}-${Math.random()}`;function H3(e,t){const n={},r=(a,l)=>{let s=a.clone();return s=(l==null?void 0:l(s))||s,s.toRgbString()},o=(a,l)=>{const s=new Mt(a),c=Ai(s.toRgbString());n[`${l}-color`]=r(s),n[`${l}-color-disabled`]=c[1],n[`${l}-color-hover`]=c[4],n[`${l}-color-active`]=c[6],n[`${l}-color-outline`]=s.clone().setAlpha(.2).toRgbString(),n[`${l}-color-deprecated-bg`]=c[0],n[`${l}-color-deprecated-border`]=c[2]};if(t.primaryColor){o(t.primaryColor,"primary");const a=new Mt(t.primaryColor),l=Ai(a.toRgbString());l.forEach((c,u)=>{n[`primary-${u+1}`]=c}),n["primary-color-deprecated-l-35"]=r(a,c=>c.lighten(35)),n["primary-color-deprecated-l-20"]=r(a,c=>c.lighten(20)),n["primary-color-deprecated-t-20"]=r(a,c=>c.tint(20)),n["primary-color-deprecated-t-50"]=r(a,c=>c.tint(50)),n["primary-color-deprecated-f-12"]=r(a,c=>c.setAlpha(c.getAlpha()*.12));const s=new Mt(l[0]);n["primary-color-active-deprecated-f-30"]=r(s,c=>c.setAlpha(c.getAlpha()*.3)),n["primary-color-active-deprecated-d-02"]=r(s,c=>c.darken(2))}return t.successColor&&o(t.successColor,"success"),t.warningColor&&o(t.warningColor,"warning"),t.errorColor&&o(t.errorColor,"error"),t.infoColor&&o(t.infoColor,"info"),` + :root { + ${Object.keys(n).map(a=>`--${e}-${a}: ${n[a]};`).join(` +`)} + } + `.trim()}function W3(e,t){const n=H3(e,t);Rn()&&Xo(n,`${j3}-dynamic-theme`)}const Xp=f.exports.createContext(!1),V3=e=>{let{children:t,disabled:n}=e;const r=f.exports.useContext(Xp);return C(Xp.Provider,{value:n!=null?n:r,children:t})},rl=Xp,Qp=f.exports.createContext(void 0),U3=e=>{let{children:t,size:n}=e;const r=f.exports.useContext(Qp);return C(Qp.Provider,{value:n||r,children:t})},qd=Qp;function Y3(){const e=f.exports.useContext(rl),t=f.exports.useContext(qd);return{componentDisabled:e,componentSize:t}}const $s=["blue","purple","cyan","green","magenta","pink","red","orange","yellow","volcano","geekblue","lime","gold"],G3="5.14.2";function rv(e){return e>=0&&e<=255}function Oc(e,t){const{r:n,g:r,b:o,a:i}=new Mt(e).toRgb();if(i<1)return e;const{r:a,g:l,b:s}=new Mt(t).toRgb();for(let c=.01;c<=1;c+=.01){const u=Math.round((n-a*(1-c))/c),d=Math.round((r-l*(1-c))/c),v=Math.round((o-s*(1-c))/c);if(rv(u)&&rv(d)&&rv(v))return new Mt({r:u,g:d,b:v,a:Math.round(c*100)/100}).toRgbString()}return new Mt({r:n,g:r,b:o,a:1}).toRgbString()}var K3=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{delete r[v]});const o=Object.assign(Object.assign({},n),r),i=480,a=576,l=768,s=992,c=1200,u=1600;if(o.motion===!1){const v="0s";o.motionDurationFast=v,o.motionDurationMid=v,o.motionDurationSlow=v}return Object.assign(Object.assign(Object.assign({},o),{colorFillContent:o.colorFillSecondary,colorFillContentHover:o.colorFill,colorFillAlter:o.colorFillQuaternary,colorBgContainerDisabled:o.colorFillTertiary,colorBorderBg:o.colorBgContainer,colorSplit:Oc(o.colorBorderSecondary,o.colorBgContainer),colorTextPlaceholder:o.colorTextQuaternary,colorTextDisabled:o.colorTextQuaternary,colorTextHeading:o.colorText,colorTextLabel:o.colorTextSecondary,colorTextDescription:o.colorTextTertiary,colorTextLightSolid:o.colorWhite,colorHighlight:o.colorError,colorBgTextHover:o.colorFillSecondary,colorBgTextActive:o.colorFill,colorIcon:o.colorTextTertiary,colorIconHover:o.colorText,colorErrorOutline:Oc(o.colorErrorBg,o.colorBgContainer),colorWarningOutline:Oc(o.colorWarningBg,o.colorBgContainer),fontSizeIcon:o.fontSizeSM,lineWidthFocus:o.lineWidth*4,lineWidth:o.lineWidth,controlOutlineWidth:o.lineWidth*2,controlInteractiveSize:o.controlHeight/2,controlItemBgHover:o.colorFillTertiary,controlItemBgActive:o.colorPrimaryBg,controlItemBgActiveHover:o.colorPrimaryBgHover,controlItemBgActiveDisabled:o.colorFill,controlTmpOutline:o.colorFillQuaternary,controlOutline:Oc(o.colorPrimaryBg,o.colorBgContainer),lineType:o.lineType,borderRadius:o.borderRadius,borderRadiusXS:o.borderRadiusXS,borderRadiusSM:o.borderRadiusSM,borderRadiusLG:o.borderRadiusLG,fontWeightStrong:600,opacityLoading:.65,linkDecoration:"none",linkHoverDecoration:"none",linkFocusDecoration:"none",controlPaddingHorizontal:12,controlPaddingHorizontalSM:8,paddingXXS:o.sizeXXS,paddingXS:o.sizeXS,paddingSM:o.sizeSM,padding:o.size,paddingMD:o.sizeMD,paddingLG:o.sizeLG,paddingXL:o.sizeXL,paddingContentHorizontalLG:o.sizeLG,paddingContentVerticalLG:o.sizeMS,paddingContentHorizontal:o.sizeMS,paddingContentVertical:o.sizeSM,paddingContentHorizontalSM:o.size,paddingContentVerticalSM:o.sizeXS,marginXXS:o.sizeXXS,marginXS:o.sizeXS,marginSM:o.sizeSM,margin:o.size,marginMD:o.sizeMD,marginLG:o.sizeLG,marginXL:o.sizeXL,marginXXL:o.sizeXXL,boxShadow:` + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowSecondary:` + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowTertiary:` + 0 1px 2px 0 rgba(0, 0, 0, 0.03), + 0 1px 6px -1px rgba(0, 0, 0, 0.02), + 0 2px 4px 0 rgba(0, 0, 0, 0.02) + `,screenXS:i,screenXSMin:i,screenXSMax:a-1,screenSM:a,screenSMMin:a,screenSMMax:l-1,screenMD:l,screenMDMin:l,screenMDMax:s-1,screenLG:s,screenLGMin:s,screenLGMax:c-1,screenXL:c,screenXLMin:c,screenXLMax:u-1,screenXXL:u,screenXXLMin:u,boxShadowPopoverArrow:"2px 2px 5px rgba(0, 0, 0, 0.05)",boxShadowCard:` + 0 1px 2px -2px ${new Mt("rgba(0, 0, 0, 0.16)").toRgbString()}, + 0 3px 6px 0 ${new Mt("rgba(0, 0, 0, 0.12)").toRgbString()}, + 0 5px 12px 4px ${new Mt("rgba(0, 0, 0, 0.09)").toRgbString()} + `,boxShadowDrawerRight:` + -6px 0 16px 0 rgba(0, 0, 0, 0.08), + -3px 0 6px -4px rgba(0, 0, 0, 0.12), + -9px 0 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowDrawerLeft:` + 6px 0 16px 0 rgba(0, 0, 0, 0.08), + 3px 0 6px -4px rgba(0, 0, 0, 0.12), + 9px 0 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowDrawerUp:` + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowDrawerDown:` + 0 -6px 16px 0 rgba(0, 0, 0, 0.08), + 0 -3px 6px -4px rgba(0, 0, 0, 0.12), + 0 -9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowTabsOverflowLeft:"inset 10px 0 8px -8px rgba(0, 0, 0, 0.08)",boxShadowTabsOverflowRight:"inset -10px 0 8px -8px rgba(0, 0, 0, 0.08)",boxShadowTabsOverflowTop:"inset 0 10px 8px -8px rgba(0, 0, 0, 0.08)",boxShadowTabsOverflowBottom:"inset 0 -10px 8px -8px rgba(0, 0, 0, 0.08)"}),r)}var Iy=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const r=n.getDerivativeToken(e),{override:o}=t,i=Iy(t,["override"]);let a=Object.assign(Object.assign({},r),{override:o});return a=Kx(a),i&&Object.entries(i).forEach(l=>{let[s,c]=l;const{theme:u}=c,d=Iy(c,["theme"]);let v=d;u&&(v=Qx(Object.assign(Object.assign({},a),d),{override:d},u)),a[s]=v}),a};function Kn(){const{token:e,hashed:t,theme:n,override:r,cssVar:o}=lt.useContext(Yx),i=`${G3}-${t||""}`,a=n||Ux,[l,s,c]=AT(a,[ws,e],{salt:i,override:r,getComputedToken:Qx,formatToken:Kx,cssVar:o&&{prefix:o.prefix,key:o.key,unitless:qx,ignore:Xx,preserve:q3}});return[a,c,t?s:"",l,o]}function hn(e){var t=f.exports.useRef();t.current=e;var n=f.exports.useCallback(function(){for(var r,o=arguments.length,i=new Array(o),a=0;a1&&arguments[1]!==void 0?arguments[1]:!1;return{boxSizing:"border-box",margin:0,padding:0,color:e.colorText,fontSize:e.fontSize,lineHeight:e.lineHeight,listStyle:"none",fontFamily:t?"inherit":e.fontFamily}},Uh=()=>({display:"inline-flex",alignItems:"center",color:"inherit",fontStyle:"normal",lineHeight:0,textAlign:"center",textTransform:"none",verticalAlign:"-0.125em",textRendering:"optimizeLegibility","-webkit-font-smoothing":"antialiased","-moz-osx-font-smoothing":"grayscale","> *":{lineHeight:1},svg:{display:"inline-block"}}),Us=()=>({"&::before":{display:"table",content:'""'},"&::after":{display:"table",clear:"both",content:'""'}}),X3=e=>({a:{color:e.colorLink,textDecoration:e.linkDecoration,backgroundColor:"transparent",outline:"none",cursor:"pointer",transition:`color ${e.motionDurationSlow}`,"-webkit-text-decoration-skip":"objects","&:hover":{color:e.colorLinkHover},"&:active":{color:e.colorLinkActive},[`&:active, + &:hover`]:{textDecoration:e.linkHoverDecoration,outline:0},"&:focus":{textDecoration:e.linkFocusDecoration,outline:0},"&[disabled]":{color:e.colorTextDisabled,cursor:"not-allowed"}}}),Q3=(e,t,n)=>{const{fontFamily:r,fontSize:o}=e,i=`[class^="${t}"], [class*=" ${t}"]`;return{[n?`.${n}`:i]:{fontFamily:r,fontSize:o,boxSizing:"border-box","&::before, &::after":{boxSizing:"border-box"},[i]:{boxSizing:"border-box","&::before, &::after":{boxSizing:"border-box"}}}}},Yh=e=>({outline:`${X(e.lineWidthFocus)} solid ${e.colorPrimaryBorder}`,outlineOffset:1,transition:"outline-offset 0s, outline 0s"}),Xd=e=>({"&:focus-visible":Object.assign({},Yh(e))});let Z3=Fn(function e(){zn(this,e)});const Zx=Z3;function J3(e,t,n){return t=Zo(t),Fh(e,Ud()?Reflect.construct(t,n||[],Zo(e).constructor):t.apply(e,n))}let e5=function(e){Bi(t,e);function t(n){var r;return zn(this,t),r=J3(this,t),r.result=0,n instanceof t?r.result=n.result:typeof n=="number"&&(r.result=n),r}return Fn(t,[{key:"add",value:function(r){return r instanceof t?this.result+=r.result:typeof r=="number"&&(this.result+=r),this}},{key:"sub",value:function(r){return r instanceof t?this.result-=r.result:typeof r=="number"&&(this.result-=r),this}},{key:"mul",value:function(r){return r instanceof t?this.result*=r.result:typeof r=="number"&&(this.result*=r),this}},{key:"div",value:function(r){return r instanceof t?this.result/=r.result:typeof r=="number"&&(this.result/=r),this}},{key:"equal",value:function(){return this.result}}]),t}(Zx);function t5(e,t,n){return t=Zo(t),Fh(e,Ud()?Reflect.construct(t,n||[],Zo(e).constructor):t.apply(e,n))}const Jx="CALC_UNIT";function iv(e){return typeof e=="number"?`${e}${Jx}`:e}let n5=function(e){Bi(t,e);function t(n){var r;return zn(this,t),r=t5(this,t),r.result="",n instanceof t?r.result=`(${n.result})`:typeof n=="number"?r.result=iv(n):typeof n=="string"&&(r.result=n),r}return Fn(t,[{key:"add",value:function(r){return r instanceof t?this.result=`${this.result} + ${r.getResult()}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} + ${iv(r)}`),this.lowPriority=!0,this}},{key:"sub",value:function(r){return r instanceof t?this.result=`${this.result} - ${r.getResult()}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} - ${iv(r)}`),this.lowPriority=!0,this}},{key:"mul",value:function(r){return this.lowPriority&&(this.result=`(${this.result})`),r instanceof t?this.result=`${this.result} * ${r.getResult(!0)}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} * ${r}`),this.lowPriority=!1,this}},{key:"div",value:function(r){return this.lowPriority&&(this.result=`(${this.result})`),r instanceof t?this.result=`${this.result} / ${r.getResult(!0)}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} / ${r}`),this.lowPriority=!1,this}},{key:"getResult",value:function(r){return this.lowPriority||r?`(${this.result})`:this.result}},{key:"equal",value:function(r){const{unit:o=!0}=r||{},i=new RegExp(`${Jx}`,"g");return this.result=this.result.replace(i,o?"px":""),typeof this.lowPriority<"u"?`calc(${this.result})`:this.result}}]),t}(Zx);const r5=e=>{const t=e==="css"?n5:e5;return n=>new t(n)},o5=r5;function i5(e){return e==="js"?{max:Math.max,min:Math.min}:{max:function(){for(var t=arguments.length,n=new Array(t),r=0;rX(o)).join(",")})`},min:function(){for(var t=arguments.length,n=new Array(t),r=0;rX(o)).join(",")})`}}}const ew=typeof CSSINJS_STATISTIC<"u";let Zp=!0;function $t(){for(var e=arguments.length,t=new Array(e),n=0;n{Object.keys(o).forEach(a=>{Object.defineProperty(r,a,{configurable:!0,enumerable:!0,get:()=>o[a]})})}),Zp=!0,r}const Py={};function a5(){}const l5=e=>{let t,n=e,r=a5;return ew&&typeof Proxy<"u"&&(t=new Set,n=new Proxy(e,{get(o,i){return Zp&&t.add(i),o[i]}}),r=(o,i)=>{var a;Py[o]={global:Array.from(t),component:Object.assign(Object.assign({},(a=Py[o])===null||a===void 0?void 0:a.component),i)}}),{token:n,keys:t,flush:r}},s5=(e,t)=>{const[n,r]=Kn();return Gp({theme:n,token:r,hashId:"",path:["ant-design-icons",e],nonce:()=>t==null?void 0:t.nonce},()=>[{[`.${e}`]:Object.assign(Object.assign({},Uh()),{[`.${e} .${e}-icon`]:{display:"block"}})}])},tw=s5,nw=(e,t,n)=>{var r;return typeof n=="function"?n($t(t,(r=t[e])!==null&&r!==void 0?r:{})):n!=null?n:{}},rw=(e,t,n,r)=>{const o=Object.assign({},t[e]);if(r!=null&&r.deprecatedTokens){const{deprecatedTokens:a}=r;a.forEach(l=>{let[s,c]=l;var u;((o==null?void 0:o[s])||(o==null?void 0:o[c]))&&((u=o[c])!==null&&u!==void 0||(o[c]=o==null?void 0:o[s]))})}const i=Object.assign(Object.assign({},n),o);return Object.keys(i).forEach(a=>{i[a]===t[a]&&delete i[a]}),i},c5=(e,t)=>`${[t,e.replace(/([A-Z]+)([A-Z][a-z]+)/g,"$1-$2").replace(/([a-z])([A-Z])/g,"$1-$2")].filter(Boolean).join("-")}`;function Gh(e,t,n){let r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};const o=Array.isArray(e)?e:[e,e],[i]=o,a=o.join("-");return function(l){let s=arguments.length>1&&arguments[1]!==void 0?arguments[1]:l;const[c,u,d,v,h]=Kn(),{getPrefixCls:g,iconPrefixCls:p,csp:b}=f.exports.useContext(ot),m=g(),y=h?"css":"js",S=o5(y),{max:x,min:$}=i5(y),E={theme:c,token:v,hashId:d,nonce:()=>b==null?void 0:b.nonce,clientOnly:r.clientOnly,order:r.order||-999};return Gp(Object.assign(Object.assign({},E),{clientOnly:!1,path:["Shared",m]}),()=>[{"&":X3(v)}]),tw(p,b),[Gp(Object.assign(Object.assign({},E),{path:[a,l,p]}),()=>{if(r.injectStyle===!1)return[];const{token:R,flush:P}=l5(v),N=nw(i,u,n),I=`.${l}`,z=rw(i,u,N,{deprecatedTokens:r.deprecatedTokens});h&&Object.keys(N).forEach(D=>{N[D]=`var(${$x(D,c5(i,h.prefix))})`});const F=$t(R,{componentCls:I,prefixCls:l,iconCls:`.${p}`,antCls:`.${m}`,calc:S,max:x,min:$},h?N:z),T=t(F,{hashId:d,prefixCls:l,rootPrefixCls:m,iconPrefixCls:p});return P(i,z),[r.resetStyle===!1?null:Q3(F,l,s),T]}),d]}}const Kh=(e,t,n,r)=>{const o=Gh(e,t,n,Object.assign({resetStyle:!1,order:-998},r));return a=>{let{prefixCls:l,rootCls:s=l}=a;return o(l,s),null}},u5=(e,t,n)=>{function r(c){return`${e}${c.slice(0,1).toUpperCase()}${c.slice(1)}`}const{unitless:o={},injectStyle:i=!0}=n!=null?n:{},a={[r("zIndexPopup")]:!0};Object.keys(o).forEach(c=>{a[r(c)]=o[c]});const l=c=>{let{rootCls:u,cssVar:d}=c;const[,v]=Kn();return s3({path:[e],prefix:d.prefix,key:d==null?void 0:d.key,unitless:Object.assign(Object.assign({},qx),a),ignore:Xx,token:v,scope:u},()=>{const h=nw(e,v,t),g=rw(e,v,h,{deprecatedTokens:n==null?void 0:n.deprecatedTokens});return Object.keys(h).forEach(p=>{g[r(p)]=g[p],delete g[p]}),g}),null};return c=>{const[,,,,u]=Kn();return[d=>i&&u?ie(Tt,{children:[C(l,{rootCls:c,cssVar:u,component:e}),d]}):d,u==null?void 0:u.key]}},vn=(e,t,n,r)=>{const o=Gh(e,t,n,r),i=u5(Array.isArray(e)?e[0]:e,n,r);return function(a){let l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:a;const[,s]=o(a,l),[c,u]=i(l);return[c,s,u]}};function ow(e,t){return $s.reduce((n,r)=>{const o=e[`${r}1`],i=e[`${r}3`],a=e[`${r}6`],l=e[`${r}7`];return Object.assign(Object.assign({},n),t(r,{lightColor:o,lightBorderColor:i,darkColor:a,textColor:l}))},{})}const d5=Object.assign({},As),{useId:Ty}=d5,f5=()=>"",v5=typeof Ty>"u"?f5:Ty,p5=v5;function g5(e,t){var n;jx();const r=e||{},o=r.inherit===!1||!t?Object.assign(Object.assign({},qp),{hashed:(n=t==null?void 0:t.hashed)!==null&&n!==void 0?n:qp.hashed,cssVar:t==null?void 0:t.cssVar}):t,i=p5();return Hs(()=>{var a,l;if(!e)return t;const s=Object.assign({},o.components);Object.keys(e.components||{}).forEach(d=>{s[d]=Object.assign(Object.assign({},s[d]),e.components[d])});const c=`css-var-${i.replace(/:/g,"")}`,u=((a=r.cssVar)!==null&&a!==void 0?a:o.cssVar)&&Object.assign(Object.assign(Object.assign({prefix:"ant"},typeof o.cssVar=="object"?o.cssVar:{}),typeof r.cssVar=="object"?r.cssVar:{}),{key:typeof r.cssVar=="object"&&((l=r.cssVar)===null||l===void 0?void 0:l.key)||c});return Object.assign(Object.assign(Object.assign({},o),r),{token:Object.assign(Object.assign({},o.token),r.token),components:s,cssVar:u})},[r,o],(a,l)=>a.some((s,c)=>{const u=l[c];return!Vs(s,u,!0)}))}var h5=["children"],iw=f.exports.createContext({});function m5(e){var t=e.children,n=Je(e,h5);return C(iw.Provider,{value:n,children:t})}var y5=function(e){Bi(n,e);var t=Ws(n);function n(){return zn(this,n),t.apply(this,arguments)}return Fn(n,[{key:"render",value:function(){return this.props.children}}]),n}(f.exports.Component),vi="none",Rc="appear",Ic="enter",Pc="leave",Ny="none",Nr="prepare",xa="start",wa="active",qh="end",aw="prepared";function _y(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit".concat(e)]="webkit".concat(t),n["Moz".concat(e)]="moz".concat(t),n["ms".concat(e)]="MS".concat(t),n["O".concat(e)]="o".concat(t.toLowerCase()),n}function b5(e,t){var n={animationend:_y("Animation","AnimationEnd"),transitionend:_y("Transition","TransitionEnd")};return e&&("AnimationEvent"in t||delete n.animationend.animation,"TransitionEvent"in t||delete n.transitionend.transition),n}var S5=b5(Rn(),typeof window<"u"?window:{}),lw={};if(Rn()){var C5=document.createElement("div");lw=C5.style}var Tc={};function sw(e){if(Tc[e])return Tc[e];var t=S5[e];if(t)for(var n=Object.keys(t),r=n.length,o=0;o1&&arguments[1]!==void 0?arguments[1]:2;t();var i=St(function(){o<=1?r({isCanceled:function(){return i!==e.current}}):n(r,o-1)});e.current=i}return f.exports.useEffect(function(){return function(){t()}},[]),[n,t]};var $5=[Nr,xa,wa,qh],E5=[Nr,aw],vw=!1,M5=!0;function pw(e){return e===wa||e===qh}const O5=function(e,t,n){var r=_a(Ny),o=G(r,2),i=o[0],a=o[1],l=w5(),s=G(l,2),c=s[0],u=s[1];function d(){a(Nr,!0)}var v=t?E5:$5;return fw(function(){if(i!==Ny&&i!==qh){var h=v.indexOf(i),g=v[h+1],p=n(i);p===vw?a(g,!0):g&&c(function(b){function m(){b.isCanceled()||a(g,!0)}p===!0?m():Promise.resolve(p).then(m)})}},[e,i]),f.exports.useEffect(function(){return function(){u()}},[]),[d,i]};function R5(e,t,n,r){var o=r.motionEnter,i=o===void 0?!0:o,a=r.motionAppear,l=a===void 0?!0:a,s=r.motionLeave,c=s===void 0?!0:s,u=r.motionDeadline,d=r.motionLeaveImmediately,v=r.onAppearPrepare,h=r.onEnterPrepare,g=r.onLeavePrepare,p=r.onAppearStart,b=r.onEnterStart,m=r.onLeaveStart,y=r.onAppearActive,S=r.onEnterActive,x=r.onLeaveActive,$=r.onAppearEnd,E=r.onEnterEnd,w=r.onLeaveEnd,R=r.onVisibleChanged,P=_a(),N=G(P,2),I=N[0],z=N[1],F=_a(vi),T=G(F,2),D=T[0],_=T[1],O=_a(null),M=G(O,2),L=M[0],A=M[1],B=f.exports.useRef(!1),k=f.exports.useRef(null);function j(){return n()}var H=f.exports.useRef(!1);function W(){_(vi,!0),A(null,!0)}function Y(oe){var se=j();if(!(oe&&!oe.deadline&&oe.target!==se)){var le=H.current,Ce;D===Rc&&le?Ce=$==null?void 0:$(se,oe):D===Ic&&le?Ce=E==null?void 0:E(se,oe):D===Pc&&le&&(Ce=w==null?void 0:w(se,oe)),D!==vi&&le&&Ce!==!1&&W()}}var K=x5(Y),q=G(K,1),ee=q[0],Z=function(se){var le,Ce,ce;switch(se){case Rc:return le={},V(le,Nr,v),V(le,xa,p),V(le,wa,y),le;case Ic:return Ce={},V(Ce,Nr,h),V(Ce,xa,b),V(Ce,wa,S),Ce;case Pc:return ce={},V(ce,Nr,g),V(ce,xa,m),V(ce,wa,x),ce;default:return{}}},Q=f.exports.useMemo(function(){return Z(D)},[D]),ne=O5(D,!e,function(oe){if(oe===Nr){var se=Q[Nr];return se?se(j()):vw}if(re in Q){var le;A(((le=Q[re])===null||le===void 0?void 0:le.call(Q,j(),null))||null)}return re===wa&&(ee(j()),u>0&&(clearTimeout(k.current),k.current=setTimeout(function(){Y({deadline:!0})},u))),re===aw&&W(),M5}),ae=G(ne,2),J=ae[0],re=ae[1],fe=pw(re);H.current=fe,fw(function(){z(t);var oe=B.current;B.current=!0;var se;!oe&&t&&l&&(se=Rc),oe&&t&&i&&(se=Ic),(oe&&!t&&c||!oe&&d&&!t&&c)&&(se=Pc);var le=Z(se);se&&(e||le[Nr])?(_(se),J()):_(vi)},[t]),f.exports.useEffect(function(){(D===Rc&&!l||D===Ic&&!i||D===Pc&&!c)&&_(vi)},[l,i,c]),f.exports.useEffect(function(){return function(){B.current=!1,clearTimeout(k.current)}},[]);var ve=f.exports.useRef(!1);f.exports.useEffect(function(){I&&(ve.current=!0),I!==void 0&&D===vi&&((ve.current||I)&&(R==null||R(I)),ve.current=!0)},[I,D]);var pe=L;return Q[Nr]&&re===xa&&(pe=U({transition:"none"},pe)),[D,re,pe,I!=null?I:t]}function I5(e){var t=e;Qe(e)==="object"&&(t=e.transitionSupport);function n(o,i){return!!(o.motionName&&t&&i!==!1)}var r=f.exports.forwardRef(function(o,i){var a=o.visible,l=a===void 0?!0:a,s=o.removeOnLeave,c=s===void 0?!0:s,u=o.forceRender,d=o.children,v=o.motionName,h=o.leavedClassName,g=o.eventProps,p=f.exports.useContext(iw),b=p.motion,m=n(o,b),y=f.exports.useRef(),S=f.exports.useRef();function x(){try{return y.current instanceof HTMLElement?y.current:ql(S.current)}catch{return null}}var $=R5(m,l,x,o),E=G($,4),w=E[0],R=E[1],P=E[2],N=E[3],I=f.exports.useRef(N);N&&(I.current=!0);var z=f.exports.useCallback(function(A){y.current=A,zh(i,A)},[i]),F,T=U(U({},g),{},{visible:l});if(!d)F=null;else if(w===vi)N?F=d(U({},T),z):!c&&I.current&&h?F=d(U(U({},T),{},{className:h}),z):u||!c&&!h?F=d(U(U({},T),{},{style:{display:"none"}}),z):F=null;else{var D,_;R===Nr?_="prepare":pw(R)?_="active":R===xa&&(_="start");var O=Ly(v,"".concat(w,"-").concat(_));F=d(U(U({},T),{},{className:te(Ly(v,w),(D={},V(D,O,O&&_),V(D,v,typeof v=="string"),D)),style:P}),z)}if(f.exports.isValidElement(F)&&ki(F)){var M=F,L=M.ref;L||(F=f.exports.cloneElement(F,{ref:z}))}return C(y5,{ref:S,children:F})});return r.displayName="CSSMotion",r}const to=I5(dw);var Jp="add",eg="keep",tg="remove",av="removed";function P5(e){var t;return e&&Qe(e)==="object"&&"key"in e?t=e:t={key:e},U(U({},t),{},{key:String(t.key)})}function ng(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[];return e.map(P5)}function T5(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[],n=[],r=0,o=t.length,i=ng(e),a=ng(t);i.forEach(function(c){for(var u=!1,d=r;d1});return s.forEach(function(c){n=n.filter(function(u){var d=u.key,v=u.status;return d!==c||v!==tg}),n.forEach(function(u){u.key===c&&(u.status=eg)})}),n}var N5=["component","children","onVisibleChanged","onAllRemoved"],_5=["status"],A5=["eventProps","visible","children","motionName","motionAppear","motionEnter","motionLeave","motionLeaveImmediately","motionDeadline","removeOnLeave","leavedClassName","onAppearPrepare","onAppearStart","onAppearActive","onAppearEnd","onEnterStart","onEnterActive","onEnterEnd","onLeaveStart","onLeaveActive","onLeaveEnd"];function D5(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:to,n=function(r){Bi(i,r);var o=Ws(i);function i(){var a;zn(this,i);for(var l=arguments.length,s=new Array(l),c=0;cnull;var F5=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);ot.endsWith("Color"))}const W5=e=>{const{prefixCls:t,iconPrefixCls:n,theme:r,holderRender:o}=e;t!==void 0&&(gw=t),r&&H5(r)&&W3(j5(),r)},V5=e=>{const{children:t,csp:n,autoInsertSpaceInButton:r,alert:o,anchor:i,form:a,locale:l,componentSize:s,direction:c,space:u,virtual:d,dropdownMatchSelectWidth:v,popupMatchSelectWidth:h,popupOverflow:g,legacyLocale:p,parentContext:b,iconPrefixCls:m,theme:y,componentDisabled:S,segmented:x,statistic:$,spin:E,calendar:w,carousel:R,cascader:P,collapse:N,typography:I,checkbox:z,descriptions:F,divider:T,drawer:D,skeleton:_,steps:O,image:M,layout:L,list:A,mentions:B,modal:k,progress:j,result:H,slider:W,breadcrumb:Y,menu:K,pagination:q,input:ee,empty:Z,badge:Q,radio:ne,rate:ae,switch:J,transfer:re,avatar:fe,message:ve,tag:pe,table:oe,card:se,tabs:le,timeline:Ce,timePicker:ce,upload:de,notification:xe,tree:he,colorPicker:ke,datePicker:we,rangePicker:ge,flex:Pe,wave:Se,dropdown:st,warning:nt,tour:Ne}=e,Ee=f.exports.useCallback((Re,be)=>{const{prefixCls:Ae}=e;if(be)return be;const Me=Ae||b.getPrefixCls("");return Re?`${Me}-${Re}`:Me},[b.getPrefixCls,e.prefixCls]),_e=m||b.iconPrefixCls||Gx,Be=n||b.csp;tw(_e,Be);const qe=g5(y,b.theme),it={csp:Be,autoInsertSpaceInButton:r,alert:o,anchor:i,locale:l||p,direction:c,space:u,virtual:d,popupMatchSelectWidth:h!=null?h:v,popupOverflow:g,getPrefixCls:Ee,iconPrefixCls:_e,theme:qe,segmented:x,statistic:$,spin:E,calendar:w,carousel:R,cascader:P,collapse:N,typography:I,checkbox:z,descriptions:F,divider:T,drawer:D,skeleton:_,steps:O,image:M,input:ee,layout:L,list:A,mentions:B,modal:k,progress:j,result:H,slider:W,breadcrumb:Y,menu:K,pagination:q,empty:Z,badge:Q,radio:ne,rate:ae,switch:J,transfer:re,avatar:fe,message:ve,tag:pe,table:oe,card:se,tabs:le,timeline:Ce,timePicker:ce,upload:de,notification:xe,tree:he,colorPicker:ke,datePicker:we,rangePicker:ge,flex:Pe,wave:Se,dropdown:st,warning:nt,tour:Ne},ft=Object.assign({},b);Object.keys(it).forEach(Re=>{it[Re]!==void 0&&(ft[Re]=it[Re])}),k5.forEach(Re=>{const be=e[Re];be&&(ft[Re]=be)});const ut=Hs(()=>ft,ft,(Re,be)=>{const Ae=Object.keys(Re),Me=Object.keys(be);return Ae.length!==Me.length||Ae.some($e=>Re[$e]!==be[$e])}),Ue=f.exports.useMemo(()=>({prefixCls:_e,csp:Be}),[_e,Be]);let He=ie(Tt,{children:[C(z5,{dropdownMatchSelectWidth:v}),t]});const Xe=f.exports.useMemo(()=>{var Re,be,Ae,Me;return Ca(((Re=Jo.Form)===null||Re===void 0?void 0:Re.defaultValidateMessages)||{},((Ae=(be=ut.locale)===null||be===void 0?void 0:be.Form)===null||Ae===void 0?void 0:Ae.defaultValidateMessages)||{},((Me=ut.form)===null||Me===void 0?void 0:Me.validateMessages)||{},(a==null?void 0:a.validateMessages)||{})},[ut,a==null?void 0:a.validateMessages]);Object.keys(Xe).length>0&&(He=C(p3.Provider,{value:Xe,children:He})),l&&(He=C(E3,{locale:l,_ANT_MARK__:w3,children:He})),(_e||Be)&&(He=C(Th.Provider,{value:Ue,children:He})),s&&(He=C(U3,{size:s,children:He})),He=C(L5,{children:He});const Le=f.exports.useMemo(()=>{const Re=qe||{},{algorithm:be,token:Ae,components:Me,cssVar:$e}=Re,Te=F5(Re,["algorithm","token","components","cssVar"]),ye=be&&(!Array.isArray(be)||be.length>0)?Bp(be):Ux,Ge={};Object.entries(Me||{}).forEach(et=>{let[ht,mt]=et;const ct=Object.assign({},mt);"algorithm"in ct&&(ct.algorithm===!0?ct.theme=ye:(Array.isArray(ct.algorithm)||typeof ct.algorithm=="function")&&(ct.theme=Bp(ct.algorithm)),delete ct.algorithm),Ge[ht]=ct});const Ze=Object.assign(Object.assign({},ws),Ae);return Object.assign(Object.assign({},Te),{theme:ye,token:Ze,components:Ge,override:Object.assign({override:Ze},Ge),cssVar:$e})},[qe]);return y&&(He=C(Yx.Provider,{value:Le,children:He})),ut.warning&&(He=C(v3.Provider,{value:ut.warning,children:He})),S!==void 0&&(He=C(V3,{disabled:S,children:He})),C(ot.Provider,{value:ut,children:He})},ai=e=>{const t=f.exports.useContext(ot),n=f.exports.useContext(Vh);return C(V5,{...Object.assign({parentContext:t,legacyLocale:n},e)})};ai.ConfigContext=ot;ai.SizeContext=qd;ai.config=W5;ai.useConfig=Y3;Object.defineProperty(ai,"SizeContext",{get:()=>qd});var U5=`accept acceptCharset accessKey action allowFullScreen allowTransparency + alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge + charSet checked classID className colSpan cols content contentEditable contextMenu + controls coords crossOrigin data dateTime default defer dir disabled download draggable + encType form formAction formEncType formMethod formNoValidate formTarget frameBorder + headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity + is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media + mediaGroup method min minLength multiple muted name noValidate nonce open + optimum pattern placeholder poster preload radioGroup readOnly rel required + reversed role rowSpan rows sandbox scope scoped scrolling seamless selected + shape size sizes span spellCheck src srcDoc srcLang srcSet start step style + summary tabIndex target title type useMap value width wmode wrap`,Y5=`onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown + onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick + onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown + onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel + onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough + onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata + onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError`,G5="".concat(U5," ").concat(Y5).split(/[\s\n]+/),K5="aria-",q5="data-";function zy(e,t){return e.indexOf(t)===0}function Ka(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n;t===!1?n={aria:!0,data:!0,attr:!0}:t===!0?n={aria:!0}:n=U({},t);var r={};return Object.keys(e).forEach(function(o){(n.aria&&(o==="role"||zy(o,K5))||n.data&&zy(o,q5)||n.attr&&G5.includes(o))&&(r[o]=e[o])}),r}const{isValidElement:Es}=As;function hw(e){return e&&Es(e)&&e.type===f.exports.Fragment}function X5(e,t,n){return Es(e)?f.exports.cloneElement(e,typeof n=="function"?n(e.props||{}):n):t}function ti(e,t){return X5(e,e,t)}const Q5=e=>{const[,,,,t]=Kn();return t?`${e}-css-var`:""},no=Q5;var ue={MAC_ENTER:3,BACKSPACE:8,TAB:9,NUM_CENTER:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,PRINT_SCREEN:44,INSERT:45,DELETE:46,ZERO:48,ONE:49,TWO:50,THREE:51,FOUR:52,FIVE:53,SIX:54,SEVEN:55,EIGHT:56,NINE:57,QUESTION_MARK:63,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,META:91,WIN_KEY_RIGHT:92,CONTEXT_MENU:93,NUM_ZERO:96,NUM_ONE:97,NUM_TWO:98,NUM_THREE:99,NUM_FOUR:100,NUM_FIVE:101,NUM_SIX:102,NUM_SEVEN:103,NUM_EIGHT:104,NUM_NINE:105,NUM_MULTIPLY:106,NUM_PLUS:107,NUM_MINUS:109,NUM_PERIOD:110,NUM_DIVISION:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,NUMLOCK:144,SEMICOLON:186,DASH:189,EQUALS:187,COMMA:188,PERIOD:190,SLASH:191,APOSTROPHE:192,SINGLE_QUOTE:222,OPEN_SQUARE_BRACKET:219,BACKSLASH:220,CLOSE_SQUARE_BRACKET:221,WIN_KEY:224,MAC_FF_META:224,WIN_IME:229,isTextModifyingKeyEvent:function(t){var n=t.keyCode;if(t.altKey&&!t.ctrlKey||t.metaKey||n>=ue.F1&&n<=ue.F12)return!1;switch(n){case ue.ALT:case ue.CAPS_LOCK:case ue.CONTEXT_MENU:case ue.CTRL:case ue.DOWN:case ue.END:case ue.ESC:case ue.HOME:case ue.INSERT:case ue.LEFT:case ue.MAC_FF_META:case ue.META:case ue.NUMLOCK:case ue.NUM_CENTER:case ue.PAGE_DOWN:case ue.PAGE_UP:case ue.PAUSE:case ue.PRINT_SCREEN:case ue.RIGHT:case ue.SHIFT:case ue.UP:case ue.WIN_KEY:case ue.WIN_KEY_RIGHT:return!1;default:return!0}},isCharacterKey:function(t){if(t>=ue.ZERO&&t<=ue.NINE||t>=ue.NUM_ZERO&&t<=ue.NUM_MULTIPLY||t>=ue.A&&t<=ue.Z||window.navigator.userAgent.indexOf("WebKit")!==-1&&t===0)return!0;switch(t){case ue.SPACE:case ue.QUESTION_MARK:case ue.NUM_PLUS:case ue.NUM_MINUS:case ue.NUM_PERIOD:case ue.NUM_DIVISION:case ue.SEMICOLON:case ue.DASH:case ue.EQUALS:case ue.COMMA:case ue.PERIOD:case ue.SLASH:case ue.APOSTROPHE:case ue.SINGLE_QUOTE:case ue.OPEN_SQUARE_BRACKET:case ue.BACKSLASH:case ue.CLOSE_SQUARE_BRACKET:return!0;default:return!1}}};const Z5=lt.createContext(void 0),mw=Z5,pi=100,J5=10,eN=pi*J5,yw={Modal:pi,Drawer:pi,Popover:pi,Popconfirm:pi,Tooltip:pi,Tour:pi},tN={SelectLike:50,Dropdown:50,DatePicker:50,Menu:50,ImagePreview:1};function nN(e){return e in yw}function Qd(e,t){const[,n]=Kn(),r=lt.useContext(mw),o=nN(e);if(t!==void 0)return[t,t];let i=r!=null?r:0;return o?(i+=(r?0:n.zIndexPopupBase)+yw[e],i=Math.min(i,n.zIndexPopupBase+eN)):i+=tN[e],[r===void 0?t:i,i]}function An(){An=function(){return t};var e,t={},n=Object.prototype,r=n.hasOwnProperty,o=Object.defineProperty||function(_,O,M){_[O]=M.value},i=typeof Symbol=="function"?Symbol:{},a=i.iterator||"@@iterator",l=i.asyncIterator||"@@asyncIterator",s=i.toStringTag||"@@toStringTag";function c(_,O,M){return Object.defineProperty(_,O,{value:M,enumerable:!0,configurable:!0,writable:!0}),_[O]}try{c({},"")}catch{c=function(M,L,A){return M[L]=A}}function u(_,O,M,L){var A=O&&O.prototype instanceof m?O:m,B=Object.create(A.prototype),k=new T(L||[]);return o(B,"_invoke",{value:N(_,M,k)}),B}function d(_,O,M){try{return{type:"normal",arg:_.call(O,M)}}catch(L){return{type:"throw",arg:L}}}t.wrap=u;var v="suspendedStart",h="suspendedYield",g="executing",p="completed",b={};function m(){}function y(){}function S(){}var x={};c(x,a,function(){return this});var $=Object.getPrototypeOf,E=$&&$($(D([])));E&&E!==n&&r.call(E,a)&&(x=E);var w=S.prototype=m.prototype=Object.create(x);function R(_){["next","throw","return"].forEach(function(O){c(_,O,function(M){return this._invoke(O,M)})})}function P(_,O){function M(A,B,k,j){var H=d(_[A],_,B);if(H.type!=="throw"){var W=H.arg,Y=W.value;return Y&&Qe(Y)=="object"&&r.call(Y,"__await")?O.resolve(Y.__await).then(function(K){M("next",K,k,j)},function(K){M("throw",K,k,j)}):O.resolve(Y).then(function(K){W.value=K,k(W)},function(K){return M("throw",K,k,j)})}j(H.arg)}var L;o(this,"_invoke",{value:function(B,k){function j(){return new O(function(H,W){M(B,k,H,W)})}return L=L?L.then(j,j):j()}})}function N(_,O,M){var L=v;return function(A,B){if(L===g)throw new Error("Generator is already running");if(L===p){if(A==="throw")throw B;return{value:e,done:!0}}for(M.method=A,M.arg=B;;){var k=M.delegate;if(k){var j=I(k,M);if(j){if(j===b)continue;return j}}if(M.method==="next")M.sent=M._sent=M.arg;else if(M.method==="throw"){if(L===v)throw L=p,M.arg;M.dispatchException(M.arg)}else M.method==="return"&&M.abrupt("return",M.arg);L=g;var H=d(_,O,M);if(H.type==="normal"){if(L=M.done?p:h,H.arg===b)continue;return{value:H.arg,done:M.done}}H.type==="throw"&&(L=p,M.method="throw",M.arg=H.arg)}}}function I(_,O){var M=O.method,L=_.iterator[M];if(L===e)return O.delegate=null,M==="throw"&&_.iterator.return&&(O.method="return",O.arg=e,I(_,O),O.method==="throw")||M!=="return"&&(O.method="throw",O.arg=new TypeError("The iterator does not provide a '"+M+"' method")),b;var A=d(L,_.iterator,O.arg);if(A.type==="throw")return O.method="throw",O.arg=A.arg,O.delegate=null,b;var B=A.arg;return B?B.done?(O[_.resultName]=B.value,O.next=_.nextLoc,O.method!=="return"&&(O.method="next",O.arg=e),O.delegate=null,b):B:(O.method="throw",O.arg=new TypeError("iterator result is not an object"),O.delegate=null,b)}function z(_){var O={tryLoc:_[0]};1 in _&&(O.catchLoc=_[1]),2 in _&&(O.finallyLoc=_[2],O.afterLoc=_[3]),this.tryEntries.push(O)}function F(_){var O=_.completion||{};O.type="normal",delete O.arg,_.completion=O}function T(_){this.tryEntries=[{tryLoc:"root"}],_.forEach(z,this),this.reset(!0)}function D(_){if(_||_===""){var O=_[a];if(O)return O.call(_);if(typeof _.next=="function")return _;if(!isNaN(_.length)){var M=-1,L=function A(){for(;++M<_.length;)if(r.call(_,M))return A.value=_[M],A.done=!1,A;return A.value=e,A.done=!0,A};return L.next=L}}throw new TypeError(Qe(_)+" is not iterable")}return y.prototype=S,o(w,"constructor",{value:S,configurable:!0}),o(S,"constructor",{value:y,configurable:!0}),y.displayName=c(S,s,"GeneratorFunction"),t.isGeneratorFunction=function(_){var O=typeof _=="function"&&_.constructor;return!!O&&(O===y||(O.displayName||O.name)==="GeneratorFunction")},t.mark=function(_){return Object.setPrototypeOf?Object.setPrototypeOf(_,S):(_.__proto__=S,c(_,s,"GeneratorFunction")),_.prototype=Object.create(w),_},t.awrap=function(_){return{__await:_}},R(P.prototype),c(P.prototype,l,function(){return this}),t.AsyncIterator=P,t.async=function(_,O,M,L,A){A===void 0&&(A=Promise);var B=new P(u(_,O,M,L),A);return t.isGeneratorFunction(O)?B:B.next().then(function(k){return k.done?k.value:B.next()})},R(w),c(w,s,"Generator"),c(w,a,function(){return this}),c(w,"toString",function(){return"[object Generator]"}),t.keys=function(_){var O=Object(_),M=[];for(var L in O)M.push(L);return M.reverse(),function A(){for(;M.length;){var B=M.pop();if(B in O)return A.value=B,A.done=!1,A}return A.done=!0,A}},t.values=D,T.prototype={constructor:T,reset:function(O){if(this.prev=0,this.next=0,this.sent=this._sent=e,this.done=!1,this.delegate=null,this.method="next",this.arg=e,this.tryEntries.forEach(F),!O)for(var M in this)M.charAt(0)==="t"&&r.call(this,M)&&!isNaN(+M.slice(1))&&(this[M]=e)},stop:function(){this.done=!0;var O=this.tryEntries[0].completion;if(O.type==="throw")throw O.arg;return this.rval},dispatchException:function(O){if(this.done)throw O;var M=this;function L(W,Y){return k.type="throw",k.arg=O,M.next=W,Y&&(M.method="next",M.arg=e),!!Y}for(var A=this.tryEntries.length-1;A>=0;--A){var B=this.tryEntries[A],k=B.completion;if(B.tryLoc==="root")return L("end");if(B.tryLoc<=this.prev){var j=r.call(B,"catchLoc"),H=r.call(B,"finallyLoc");if(j&&H){if(this.prev=0;--L){var A=this.tryEntries[L];if(A.tryLoc<=this.prev&&r.call(A,"finallyLoc")&&this.prev=0;--M){var L=this.tryEntries[M];if(L.finallyLoc===O)return this.complete(L.completion,L.afterLoc),F(L),b}},catch:function(O){for(var M=this.tryEntries.length-1;M>=0;--M){var L=this.tryEntries[M];if(L.tryLoc===O){var A=L.completion;if(A.type==="throw"){var B=A.arg;F(L)}return B}}throw new Error("illegal catch attempt")},delegateYield:function(O,M,L){return this.delegate={iterator:D(O),resultName:M,nextLoc:L},this.method==="next"&&(this.arg=e),b}},t}function Fy(e,t,n,r,o,i,a){try{var l=e[i](a),s=l.value}catch(c){n(c);return}l.done?t(s):Promise.resolve(s).then(r,o)}function ji(e){return function(){var t=this,n=arguments;return new Promise(function(r,o){var i=e.apply(t,n);function a(s){Fy(i,r,o,a,l,"next",s)}function l(s){Fy(i,r,o,a,l,"throw",s)}a(void 0)})}}var Ys=U({},$O),rN=Ys.version,oN=Ys.render,iN=Ys.unmountComponentAtNode,Zd;try{var aN=Number((rN||"").split(".")[0]);aN>=18&&(Zd=Ys.createRoot)}catch{}function ky(e){var t=Ys.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;t&&Qe(t)==="object"&&(t.usingClientEntryPoint=e)}var Ku="__rc_react_root__";function lN(e,t){ky(!0);var n=t[Ku]||Zd(t);ky(!1),n.render(e),t[Ku]=n}function sN(e,t){oN(e,t)}function cN(e,t){if(Zd){lN(e,t);return}sN(e,t)}function uN(e){return rg.apply(this,arguments)}function rg(){return rg=ji(An().mark(function e(t){return An().wrap(function(r){for(;;)switch(r.prev=r.next){case 0:return r.abrupt("return",Promise.resolve().then(function(){var o;(o=t[Ku])===null||o===void 0||o.unmount(),delete t[Ku]}));case 1:case"end":return r.stop()}},e)})),rg.apply(this,arguments)}function dN(e){iN(e)}function fN(e){return og.apply(this,arguments)}function og(){return og=ji(An().mark(function e(t){return An().wrap(function(r){for(;;)switch(r.prev=r.next){case 0:if(Zd===void 0){r.next=2;break}return r.abrupt("return",uN(t));case 2:dN(t);case 3:case"end":return r.stop()}},e)})),og.apply(this,arguments)}const ni=(e,t,n)=>n!==void 0?n:`${e}-${t}`,Jd=function(e){if(!e)return!1;if(e instanceof Element){if(e.offsetParent)return!0;if(e.getBBox){var t=e.getBBox(),n=t.width,r=t.height;if(n||r)return!0}if(e.getBoundingClientRect){var o=e.getBoundingClientRect(),i=o.width,a=o.height;if(i||a)return!0}}return!1},vN=e=>{const{componentCls:t,colorPrimary:n}=e;return{[t]:{position:"absolute",background:"transparent",pointerEvents:"none",boxSizing:"border-box",color:`var(--wave-color, ${n})`,boxShadow:"0 0 0 0 currentcolor",opacity:.2,"&.wave-motion-appear":{transition:[`box-shadow 0.4s ${e.motionEaseOutCirc}`,`opacity 2s ${e.motionEaseOutCirc}`].join(","),"&-active":{boxShadow:"0 0 0 6px currentcolor",opacity:0},"&.wave-quick":{transition:[`box-shadow 0.3s ${e.motionEaseInOut}`,`opacity 0.35s ${e.motionEaseInOut}`].join(",")}}}}},pN=Gh("Wave",e=>[vN(e)]);function gN(e){const t=(e||"").match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/);return t&&t[1]&&t[2]&&t[3]?!(t[1]===t[2]&&t[2]===t[3]):!0}function lv(e){return e&&e!=="#fff"&&e!=="#ffffff"&&e!=="rgb(255, 255, 255)"&&e!=="rgba(255, 255, 255, 1)"&&gN(e)&&!/rgba\((?:\d*, ){3}0\)/.test(e)&&e!=="transparent"}function hN(e){const{borderTopColor:t,borderColor:n,backgroundColor:r}=getComputedStyle(e);return lv(t)?t:lv(n)?n:lv(r)?r:null}const Xh="ant-wave-target";function sv(e){return Number.isNaN(e)?0:e}const mN=e=>{const{className:t,target:n,component:r}=e,o=f.exports.useRef(null),[i,a]=f.exports.useState(null),[l,s]=f.exports.useState([]),[c,u]=f.exports.useState(0),[d,v]=f.exports.useState(0),[h,g]=f.exports.useState(0),[p,b]=f.exports.useState(0),[m,y]=f.exports.useState(!1),S={left:c,top:d,width:h,height:p,borderRadius:l.map(E=>`${E}px`).join(" ")};i&&(S["--wave-color"]=i);function x(){const E=getComputedStyle(n);a(hN(n));const w=E.position==="static",{borderLeftWidth:R,borderTopWidth:P}=E;u(w?n.offsetLeft:sv(-parseFloat(R))),v(w?n.offsetTop:sv(-parseFloat(P))),g(n.offsetWidth),b(n.offsetHeight);const{borderTopLeftRadius:N,borderTopRightRadius:I,borderBottomLeftRadius:z,borderBottomRightRadius:F}=E;s([N,I,F,z].map(T=>sv(parseFloat(T))))}if(f.exports.useEffect(()=>{if(n){const E=St(()=>{x(),y(!0)});let w;return typeof ResizeObserver<"u"&&(w=new ResizeObserver(x),w.observe(n)),()=>{St.cancel(E),w==null||w.disconnect()}}},[]),!m)return null;const $=(r==="Checkbox"||r==="Radio")&&(n==null?void 0:n.classList.contains(Xh));return C(to,{visible:!0,motionAppear:!0,motionName:"wave-motion",motionDeadline:5e3,onAppearEnd:(E,w)=>{var R;if(w.deadline||w.propertyName==="opacity"){const P=(R=o.current)===null||R===void 0?void 0:R.parentElement;fN(P).then(()=>{P==null||P.remove()})}return!1},children:E=>{let{className:w}=E;return C("div",{ref:o,className:te(t,{"wave-quick":$},w),style:S})}})},yN=(e,t)=>{var n;const{component:r}=t;if(r==="Checkbox"&&!(!((n=e.querySelector("input"))===null||n===void 0)&&n.checked))return;const o=document.createElement("div");o.style.position="absolute",o.style.left="0px",o.style.top="0px",e==null||e.insertBefore(o,e==null?void 0:e.firstChild),cN(C(mN,{...Object.assign({},t,{target:e})}),o)},bN=yN;function SN(e,t,n){const{wave:r}=f.exports.useContext(ot),[,o,i]=Kn(),a=hn(c=>{const u=e.current;if((r==null?void 0:r.disabled)||!u)return;const d=u.querySelector(`.${Xh}`)||u,{showEffect:v}=r||{};(v||bN)(d,{className:t,token:o,component:n,event:c,hashId:i})}),l=f.exports.useRef();return c=>{St.cancel(l.current),l.current=St(()=>{a(c)})}}const CN=e=>{const{children:t,disabled:n,component:r}=e,{getPrefixCls:o}=f.exports.useContext(ot),i=f.exports.useRef(null),a=o("wave"),[,l]=pN(a),s=SN(i,te(a,l),r);if(lt.useEffect(()=>{const u=i.current;if(!u||u.nodeType!==1||n)return;const d=v=>{!Jd(v.target)||!u.getAttribute||u.getAttribute("disabled")||u.disabled||u.className.includes("disabled")||u.className.includes("-leave")||s(v)};return u.addEventListener("click",d,!0),()=>{u.removeEventListener("click",d,!0)}},[n]),!lt.isValidElement(t))return t!=null?t:null;const c=ki(t)?xr(t.ref,i):i;return ti(t,{ref:c})},Qh=CN,xN=e=>{const t=lt.useContext(qd);return lt.useMemo(()=>e?typeof e=="string"?e!=null?e:t:e instanceof Function?e(t):t:t,[e,t])},So=xN;globalThis&&globalThis.__rest;const bw=f.exports.createContext(null),ef=(e,t)=>{const n=f.exports.useContext(bw),r=f.exports.useMemo(()=>{if(!n)return"";const{compactDirection:o,isFirstItem:i,isLastItem:a}=n,l=o==="vertical"?"-vertical-":"-";return te(`${e}-compact${l}item`,{[`${e}-compact${l}first-item`]:i,[`${e}-compact${l}last-item`]:a,[`${e}-compact${l}item-rtl`]:t==="rtl"})},[e,t,n]);return{compactSize:n==null?void 0:n.compactSize,compactDirection:n==null?void 0:n.compactDirection,compactItemClassnames:r}},ig=e=>{let{children:t}=e;return C(bw.Provider,{value:null,children:t})};var wN=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{getPrefixCls:t,direction:n}=f.exports.useContext(ot),{prefixCls:r,size:o,className:i}=e,a=wN(e,["prefixCls","size","className"]),l=t("btn-group",r),[,,s]=Kn();let c="";switch(o){case"large":c="lg";break;case"small":c="sm";break}const u=te(l,{[`${l}-${c}`]:c,[`${l}-rtl`]:n==="rtl"},i,s);return C(Sw.Provider,{value:o,children:C("div",{...Object.assign({},a,{className:u})})})},EN=$N,By=/^[\u4e00-\u9fa5]{2}$/,ag=By.test.bind(By);function jy(e){return typeof e=="string"}function cv(e){return e==="text"||e==="link"}function MN(e,t){if(e==null)return;const n=t?" ":"";return typeof e!="string"&&typeof e!="number"&&jy(e.type)&&ag(e.props.children)?ti(e,{children:e.props.children.split("").join(n)}):jy(e)?ag(e)?C("span",{children:e.split("").join(n)}):C("span",{children:e}):hw(e)?C("span",{children:e}):e}function ON(e,t){let n=!1;const r=[];return lt.Children.forEach(e,o=>{const i=typeof o,a=i==="string"||i==="number";if(n&&a){const l=r.length-1,s=r[l];r[l]=`${s}${o}`}else r.push(o);n=a}),lt.Children.map(r,o=>MN(o,t))}const RN=f.exports.forwardRef((e,t)=>{const{className:n,style:r,children:o,prefixCls:i}=e,a=te(`${i}-icon`,n);return C("span",{ref:t,className:a,style:r,children:o})}),Cw=RN,Hy=f.exports.forwardRef((e,t)=>{let{prefixCls:n,className:r,style:o,iconClassName:i}=e;const a=te(`${n}-loading-icon`,r);return C(Cw,{prefixCls:n,className:a,style:o,ref:t,children:C(ux,{className:i})})}),uv=()=>({width:0,opacity:0,transform:"scale(0)"}),dv=e=>({width:e.scrollWidth,opacity:1,transform:"scale(1)"}),IN=e=>{const{prefixCls:t,loading:n,existIcon:r,className:o,style:i}=e,a=!!n;return r?C(Hy,{prefixCls:t,className:o,style:i}):C(to,{visible:a,motionName:`${t}-loading-icon-motion`,motionLeave:a,removeOnLeave:!0,onAppearStart:uv,onAppearActive:dv,onEnterStart:uv,onEnterActive:dv,onLeaveStart:dv,onLeaveActive:uv,children:(l,s)=>{let{className:c,style:u}=l;return C(Hy,{prefixCls:t,className:o,style:Object.assign(Object.assign({},i),u),ref:s,iconClassName:c})}})},PN=IN,Wy=(e,t)=>({[`> span, > ${e}`]:{"&:not(:last-child)":{[`&, & > ${e}`]:{"&:not(:disabled)":{borderInlineEndColor:t}}},"&:not(:first-child)":{[`&, & > ${e}`]:{"&:not(:disabled)":{borderInlineStartColor:t}}}}}),TN=e=>{const{componentCls:t,fontSize:n,lineWidth:r,groupBorderColor:o,colorErrorHover:i}=e;return{[`${t}-group`]:[{position:"relative",display:"inline-flex",[`> span, > ${t}`]:{"&:not(:last-child)":{[`&, & > ${t}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},"&:not(:first-child)":{marginInlineStart:e.calc(r).mul(-1).equal(),[`&, & > ${t}`]:{borderStartStartRadius:0,borderEndStartRadius:0}}},[t]:{position:"relative",zIndex:1,[`&:hover, + &:focus, + &:active`]:{zIndex:2},"&[disabled]":{zIndex:0}},[`${t}-icon-only`]:{fontSize:n}},Wy(`${t}-primary`,o),Wy(`${t}-danger`,i)]}},NN=TN,xw=e=>{const{paddingInline:t,onlyIconSize:n,paddingBlock:r}=e;return $t(e,{buttonPaddingHorizontal:t,buttonPaddingVertical:r,buttonIconOnlyFontSize:n})},ww=e=>{var t,n,r,o,i,a;const l=(t=e.contentFontSize)!==null&&t!==void 0?t:e.fontSize,s=(n=e.contentFontSizeSM)!==null&&n!==void 0?n:e.fontSize,c=(r=e.contentFontSizeLG)!==null&&r!==void 0?r:e.fontSizeLG,u=(o=e.contentLineHeight)!==null&&o!==void 0?o:ou(l),d=(i=e.contentLineHeightSM)!==null&&i!==void 0?i:ou(s),v=(a=e.contentLineHeightLG)!==null&&a!==void 0?a:ou(c);return{fontWeight:400,defaultShadow:`0 ${e.controlOutlineWidth}px 0 ${e.controlTmpOutline}`,primaryShadow:`0 ${e.controlOutlineWidth}px 0 ${e.controlOutline}`,dangerShadow:`0 ${e.controlOutlineWidth}px 0 ${e.colorErrorOutline}`,primaryColor:e.colorTextLightSolid,dangerColor:e.colorTextLightSolid,borderColorDisabled:e.colorBorder,defaultGhostColor:e.colorBgContainer,ghostBg:"transparent",defaultGhostBorderColor:e.colorBgContainer,paddingInline:e.paddingContentHorizontal-e.lineWidth,paddingInlineLG:e.paddingContentHorizontal-e.lineWidth,paddingInlineSM:8-e.lineWidth,onlyIconSize:e.fontSizeLG,onlyIconSizeSM:e.fontSizeLG-2,onlyIconSizeLG:e.fontSizeLG+2,groupBorderColor:e.colorPrimaryHover,linkHoverBg:"transparent",textHoverBg:e.colorBgTextHover,defaultColor:e.colorText,defaultBg:e.colorBgContainer,defaultBorderColor:e.colorBorder,defaultBorderColorDisabled:e.colorBorder,defaultHoverBg:e.colorBgContainer,defaultHoverColor:e.colorPrimaryHover,defaultHoverBorderColor:e.colorPrimaryHover,defaultActiveBg:e.colorBgContainer,defaultActiveColor:e.colorPrimaryActive,defaultActiveBorderColor:e.colorPrimaryActive,contentFontSize:l,contentFontSizeSM:s,contentFontSizeLG:c,contentLineHeight:u,contentLineHeightSM:d,contentLineHeightLG:v,paddingBlock:Math.max((e.controlHeight-l*u)/2-e.lineWidth,0),paddingBlockSM:Math.max((e.controlHeightSM-s*d)/2-e.lineWidth,0),paddingBlockLG:Math.max((e.controlHeightLG-c*v)/2-e.lineWidth,0)}},_N=e=>{const{componentCls:t,iconCls:n,fontWeight:r}=e;return{[t]:{outline:"none",position:"relative",display:"inline-block",fontWeight:r,whiteSpace:"nowrap",textAlign:"center",backgroundImage:"none",background:"transparent",border:`${X(e.lineWidth)} ${e.lineType} transparent`,cursor:"pointer",transition:`all ${e.motionDurationMid} ${e.motionEaseInOut}`,userSelect:"none",touchAction:"manipulation",color:e.colorText,"&:disabled > *":{pointerEvents:"none"},"> span":{display:"inline-block"},[`${t}-icon`]:{lineHeight:0},[`> ${n} + span, > span + ${n}`]:{marginInlineStart:e.marginXS},[`&:not(${t}-icon-only) > ${t}-icon`]:{[`&${t}-loading-icon, &:not(:last-child)`]:{marginInlineEnd:e.marginXS}},"> a":{color:"currentColor"},"&:not(:disabled)":Object.assign({},Xd(e)),[`&${t}-two-chinese-chars::first-letter`]:{letterSpacing:"0.34em"},[`&${t}-two-chinese-chars > *:not(${n})`]:{marginInlineEnd:"-0.34em",letterSpacing:"0.34em"},[`&-icon-only${t}-compact-item`]:{flex:"none"}}}},yo=(e,t,n)=>({[`&:not(:disabled):not(${e}-disabled)`]:{"&:hover":t,"&:active":n}}),AN=e=>({minWidth:e.controlHeight,paddingInlineStart:0,paddingInlineEnd:0,borderRadius:"50%"}),DN=e=>({borderRadius:e.controlHeight,paddingInlineStart:e.calc(e.controlHeight).div(2).equal(),paddingInlineEnd:e.calc(e.controlHeight).div(2).equal()}),LN=e=>({cursor:"not-allowed",borderColor:e.borderColorDisabled,color:e.colorTextDisabled,background:e.colorBgContainerDisabled,boxShadow:"none"}),Ms=(e,t,n,r,o,i,a,l)=>({[`&${e}-background-ghost`]:Object.assign(Object.assign({color:n||void 0,background:t,borderColor:r||void 0,boxShadow:"none"},yo(e,Object.assign({background:t},a),Object.assign({background:t},l))),{"&:disabled":{cursor:"not-allowed",color:o||void 0,borderColor:i||void 0}})}),Zh=e=>({[`&:disabled, &${e.componentCls}-disabled`]:Object.assign({},LN(e))}),$w=e=>Object.assign({},Zh(e)),qu=e=>({[`&:disabled, &${e.componentCls}-disabled`]:{cursor:"not-allowed",color:e.colorTextDisabled}}),Ew=e=>Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},$w(e)),{background:e.defaultBg,borderColor:e.defaultBorderColor,color:e.defaultColor,boxShadow:e.defaultShadow}),yo(e.componentCls,{color:e.defaultHoverColor,borderColor:e.defaultHoverBorderColor,background:e.defaultHoverBg},{color:e.defaultActiveColor,borderColor:e.defaultActiveBorderColor,background:e.defaultActiveBg})),Ms(e.componentCls,e.ghostBg,e.defaultGhostColor,e.defaultGhostBorderColor,e.colorTextDisabled,e.colorBorder)),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign(Object.assign({color:e.colorError,borderColor:e.colorError},yo(e.componentCls,{color:e.colorErrorHover,borderColor:e.colorErrorBorderHover},{color:e.colorErrorActive,borderColor:e.colorErrorActive})),Ms(e.componentCls,e.ghostBg,e.colorError,e.colorError,e.colorTextDisabled,e.colorBorder)),Zh(e))}),zN=e=>Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},$w(e)),{color:e.primaryColor,background:e.colorPrimary,boxShadow:e.primaryShadow}),yo(e.componentCls,{color:e.colorTextLightSolid,background:e.colorPrimaryHover},{color:e.colorTextLightSolid,background:e.colorPrimaryActive})),Ms(e.componentCls,e.ghostBg,e.colorPrimary,e.colorPrimary,e.colorTextDisabled,e.colorBorder,{color:e.colorPrimaryHover,borderColor:e.colorPrimaryHover},{color:e.colorPrimaryActive,borderColor:e.colorPrimaryActive})),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign(Object.assign({background:e.colorError,boxShadow:e.dangerShadow,color:e.dangerColor},yo(e.componentCls,{background:e.colorErrorHover},{background:e.colorErrorActive})),Ms(e.componentCls,e.ghostBg,e.colorError,e.colorError,e.colorTextDisabled,e.colorBorder,{color:e.colorErrorHover,borderColor:e.colorErrorHover},{color:e.colorErrorActive,borderColor:e.colorErrorActive})),Zh(e))}),FN=e=>Object.assign(Object.assign({},Ew(e)),{borderStyle:"dashed"}),kN=e=>Object.assign(Object.assign(Object.assign({color:e.colorLink},yo(e.componentCls,{color:e.colorLinkHover,background:e.linkHoverBg},{color:e.colorLinkActive})),qu(e)),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign({color:e.colorError},yo(e.componentCls,{color:e.colorErrorHover},{color:e.colorErrorActive})),qu(e))}),BN=e=>Object.assign(Object.assign(Object.assign({},yo(e.componentCls,{color:e.colorText,background:e.textHoverBg},{color:e.colorText,background:e.colorBgTextActive})),qu(e)),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign({color:e.colorError},qu(e)),yo(e.componentCls,{color:e.colorErrorHover,background:e.colorErrorBg},{color:e.colorErrorHover,background:e.colorErrorBg}))}),jN=e=>{const{componentCls:t}=e;return{[`${t}-default`]:Ew(e),[`${t}-primary`]:zN(e),[`${t}-dashed`]:FN(e),[`${t}-link`]:kN(e),[`${t}-text`]:BN(e),[`${t}-ghost`]:Ms(e.componentCls,e.ghostBg,e.colorBgContainer,e.colorBgContainer,e.colorTextDisabled,e.colorBorder)}},Jh=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"";const{componentCls:n,controlHeight:r,fontSize:o,lineHeight:i,borderRadius:a,buttonPaddingHorizontal:l,iconCls:s,buttonPaddingVertical:c}=e,u=`${n}-icon-only`;return[{[`${t}`]:{fontSize:o,lineHeight:i,height:r,padding:`${X(c)} ${X(l)}`,borderRadius:a,[`&${u}`]:{width:r,paddingInlineStart:0,paddingInlineEnd:0,[`&${n}-round`]:{width:"auto"},[s]:{fontSize:e.buttonIconOnlyFontSize}},[`&${n}-loading`]:{opacity:e.opacityLoading,cursor:"default"},[`${n}-loading-icon`]:{transition:`width ${e.motionDurationSlow} ${e.motionEaseInOut}, opacity ${e.motionDurationSlow} ${e.motionEaseInOut}`}}},{[`${n}${n}-circle${t}`]:AN(e)},{[`${n}${n}-round${t}`]:DN(e)}]},HN=e=>{const t=$t(e,{fontSize:e.contentFontSize,lineHeight:e.contentLineHeight});return Jh(t,e.componentCls)},WN=e=>{const t=$t(e,{controlHeight:e.controlHeightSM,fontSize:e.contentFontSizeSM,lineHeight:e.contentLineHeightSM,padding:e.paddingXS,buttonPaddingHorizontal:e.paddingInlineSM,buttonPaddingVertical:e.paddingBlockSM,borderRadius:e.borderRadiusSM,buttonIconOnlyFontSize:e.onlyIconSizeSM});return Jh(t,`${e.componentCls}-sm`)},VN=e=>{const t=$t(e,{controlHeight:e.controlHeightLG,fontSize:e.contentFontSizeLG,lineHeight:e.contentLineHeightLG,buttonPaddingHorizontal:e.paddingInlineLG,buttonPaddingVertical:e.paddingBlockLG,borderRadius:e.borderRadiusLG,buttonIconOnlyFontSize:e.onlyIconSizeLG});return Jh(t,`${e.componentCls}-lg`)},UN=e=>{const{componentCls:t}=e;return{[t]:{[`&${t}-block`]:{width:"100%"}}}},YN=vn("Button",e=>{const t=xw(e);return[_N(t),HN(t),WN(t),VN(t),UN(t),jN(t),NN(t)]},ww,{unitless:{fontWeight:!0,contentLineHeight:!0,contentLineHeightSM:!0,contentLineHeightLG:!0}});function GN(e,t,n){const{focusElCls:r,focus:o,borderElCls:i}=n,a=i?"> *":"",l=["hover",o?"focus":null,"active"].filter(Boolean).map(s=>`&:${s} ${a}`).join(",");return{[`&-item:not(${t}-last-item)`]:{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal()},"&-item":Object.assign(Object.assign({[l]:{zIndex:2}},r?{[`&${r}`]:{zIndex:2}}:{}),{[`&[disabled] ${a}`]:{zIndex:0}})}}function KN(e,t,n){const{borderElCls:r}=n,o=r?`> ${r}`:"";return{[`&-item:not(${t}-first-item):not(${t}-last-item) ${o}`]:{borderRadius:0},[`&-item:not(${t}-last-item)${t}-first-item`]:{[`& ${o}, &${e}-sm ${o}, &${e}-lg ${o}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&-item:not(${t}-first-item)${t}-last-item`]:{[`& ${o}, &${e}-sm ${o}, &${e}-lg ${o}`]:{borderStartStartRadius:0,borderEndStartRadius:0}}}}function tf(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{focus:!0};const{componentCls:n}=e,r=`${n}-compact`;return{[r]:Object.assign(Object.assign({},GN(e,r,t)),KN(n,r,t))}}function qN(e,t){return{[`&-item:not(${t}-last-item)`]:{marginBottom:e.calc(e.lineWidth).mul(-1).equal()},"&-item":{"&:hover,&:focus,&:active":{zIndex:2},"&[disabled]":{zIndex:0}}}}function XN(e,t){return{[`&-item:not(${t}-first-item):not(${t}-last-item)`]:{borderRadius:0},[`&-item${t}-first-item:not(${t}-last-item)`]:{[`&, &${e}-sm, &${e}-lg`]:{borderEndEndRadius:0,borderEndStartRadius:0}},[`&-item${t}-last-item:not(${t}-first-item)`]:{[`&, &${e}-sm, &${e}-lg`]:{borderStartStartRadius:0,borderStartEndRadius:0}}}}function QN(e){const t=`${e.componentCls}-compact-vertical`;return{[t]:Object.assign(Object.assign({},qN(e,t)),XN(e.componentCls,t))}}const ZN=e=>{const{componentCls:t,calc:n}=e;return{[t]:{[`&-compact-item${t}-primary`]:{[`&:not([disabled]) + ${t}-compact-item${t}-primary:not([disabled])`]:{position:"relative","&:before":{position:"absolute",top:n(e.lineWidth).mul(-1).equal(),insetInlineStart:n(e.lineWidth).mul(-1).equal(),display:"inline-block",width:e.lineWidth,height:`calc(100% + ${X(e.lineWidth)} * 2)`,backgroundColor:e.colorPrimaryHover,content:'""'}}},"&-compact-vertical-item":{[`&${t}-primary`]:{[`&:not([disabled]) + ${t}-compact-vertical-item${t}-primary:not([disabled])`]:{position:"relative","&:before":{position:"absolute",top:n(e.lineWidth).mul(-1).equal(),insetInlineStart:n(e.lineWidth).mul(-1).equal(),display:"inline-block",width:`calc(100% + ${X(e.lineWidth)} * 2)`,height:e.lineWidth,backgroundColor:e.colorPrimaryHover,content:'""'}}}}}}},JN=Kh(["Button","compact"],e=>{const t=xw(e);return[tf(t),QN(t),ZN(t)]},ww);var e6=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n,r;const{loading:o=!1,prefixCls:i,type:a="default",danger:l,shape:s="default",size:c,styles:u,disabled:d,className:v,rootClassName:h,children:g,icon:p,ghost:b=!1,block:m=!1,htmlType:y="button",classNames:S,style:x={}}=e,$=e6(e,["loading","prefixCls","type","danger","shape","size","styles","disabled","className","rootClassName","children","icon","ghost","block","htmlType","classNames","style"]),{getPrefixCls:E,autoInsertSpaceInButton:w,direction:R,button:P}=f.exports.useContext(ot),N=E("btn",i),[I,z,F]=YN(N),T=f.exports.useContext(rl),D=d!=null?d:T,_=f.exports.useContext(Sw),O=f.exports.useMemo(()=>t6(o),[o]),[M,L]=f.exports.useState(O.loading),[A,B]=f.exports.useState(!1),j=xr(t,f.exports.createRef()),H=f.exports.Children.count(g)===1&&!p&&!cv(a);f.exports.useEffect(()=>{let le=null;O.delay>0?le=setTimeout(()=>{le=null,L(!0)},O.delay):L(O.loading);function Ce(){le&&(clearTimeout(le),le=null)}return Ce},[O]),f.exports.useEffect(()=>{if(!j||!j.current||w===!1)return;const le=j.current.textContent;H&&ag(le)?A||B(!0):A&&B(!1)},[j]);const W=le=>{const{onClick:Ce}=e;if(M||D){le.preventDefault();return}Ce==null||Ce(le)},Y=w!==!1,{compactSize:K,compactItemClassnames:q}=ef(N,R),ee={large:"lg",small:"sm",middle:void 0},Z=So(le=>{var Ce,ce;return(ce=(Ce=c!=null?c:K)!==null&&Ce!==void 0?Ce:_)!==null&&ce!==void 0?ce:le}),Q=Z&&ee[Z]||"",ne=M?"loading":p,ae=lr($,["navigate"]),J=te(N,z,F,{[`${N}-${s}`]:s!=="default"&&s,[`${N}-${a}`]:a,[`${N}-${Q}`]:Q,[`${N}-icon-only`]:!g&&g!==0&&!!ne,[`${N}-background-ghost`]:b&&!cv(a),[`${N}-loading`]:M,[`${N}-two-chinese-chars`]:A&&Y&&!M,[`${N}-block`]:m,[`${N}-dangerous`]:!!l,[`${N}-rtl`]:R==="rtl"},q,v,h,P==null?void 0:P.className),re=Object.assign(Object.assign({},P==null?void 0:P.style),x),fe=te(S==null?void 0:S.icon,(n=P==null?void 0:P.classNames)===null||n===void 0?void 0:n.icon),ve=Object.assign(Object.assign({},(u==null?void 0:u.icon)||{}),((r=P==null?void 0:P.styles)===null||r===void 0?void 0:r.icon)||{}),pe=p&&!M?C(Cw,{prefixCls:N,className:fe,style:ve,children:p}):C(PN,{existIcon:!!p,prefixCls:N,loading:!!M}),oe=g||g===0?ON(g,H&&Y):null;if(ae.href!==void 0)return I(ie("a",{...Object.assign({},ae,{className:te(J,{[`${N}-disabled`]:D}),href:D?void 0:ae.href,style:re,onClick:W,ref:j,tabIndex:D?-1:0}),children:[pe,oe]}));let se=ie("button",{...Object.assign({},$,{type:y,className:J,style:re,onClick:W,disabled:D,ref:j}),children:[pe,oe,!!q&&C(JN,{prefixCls:N},"compact")]});return cv(a)||(se=C(Qh,{component:"Button",disabled:!!M,children:se})),I(se)},em=f.exports.forwardRef(n6);em.Group=EN;em.__ANT_BUTTON=!0;const Xu=em;var Mw=f.exports.createContext(null),Vy=[];function r6(e,t){var n=f.exports.useState(function(){if(!Rn())return null;var g=document.createElement("div");return g}),r=G(n,1),o=r[0],i=f.exports.useRef(!1),a=f.exports.useContext(Mw),l=f.exports.useState(Vy),s=G(l,2),c=s[0],u=s[1],d=a||(i.current?void 0:function(g){u(function(p){var b=[g].concat(Oe(p));return b})});function v(){o.parentElement||document.body.appendChild(o),i.current=!0}function h(){var g;(g=o.parentElement)===null||g===void 0||g.removeChild(o),i.current=!1}return Nt(function(){return e?a?a(v):v():h(),h},[e]),Nt(function(){c.length&&(c.forEach(function(g){return g()}),u(Vy))},[c]),[o,d]}var fv;function o6(e){if(typeof document>"u")return 0;if(e||fv===void 0){var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var n=document.createElement("div"),r=n.style;r.position="absolute",r.top="0",r.left="0",r.pointerEvents="none",r.visibility="hidden",r.width="200px",r.height="150px",r.overflow="hidden",n.appendChild(t),document.body.appendChild(n);var o=t.offsetWidth;n.style.overflow="scroll";var i=t.offsetWidth;o===i&&(i=n.clientWidth),document.body.removeChild(n),fv=o-i}return fv}function Uy(e){var t=e.match(/^(.*)px$/),n=Number(t==null?void 0:t[1]);return Number.isNaN(n)?o6():n}function i6(e){if(typeof document>"u"||!e||!(e instanceof Element))return{width:0,height:0};var t=getComputedStyle(e,"::-webkit-scrollbar"),n=t.width,r=t.height;return{width:Uy(n),height:Uy(r)}}function a6(){return document.body.scrollHeight>(window.innerHeight||document.documentElement.clientHeight)&&window.innerWidth>document.body.offsetWidth}var l6="rc-util-locker-".concat(Date.now()),Yy=0;function s6(e){var t=!!e,n=f.exports.useState(function(){return Yy+=1,"".concat(l6,"_").concat(Yy)}),r=G(n,1),o=r[0];Nt(function(){if(t){var i=i6(document.body).width,a=a6();Xo(` +html body { + overflow-y: hidden; + `.concat(a?"width: calc(100% - ".concat(i,"px);"):"",` +}`),o)}else Ss(o);return function(){Ss(o)}},[t,o])}var Gy=!1;function c6(e){return typeof e=="boolean"&&(Gy=e),Gy}var Ky=function(t){return t===!1?!1:!Rn()||!t?null:typeof t=="string"?document.querySelector(t):typeof t=="function"?t():t},nf=f.exports.forwardRef(function(e,t){var n=e.open,r=e.autoLock,o=e.getContainer;e.debug;var i=e.autoDestroy,a=i===void 0?!0:i,l=e.children,s=f.exports.useState(n),c=G(s,2),u=c[0],d=c[1],v=u||n;f.exports.useEffect(function(){(a||n)&&d(n)},[n,a]);var h=f.exports.useState(function(){return Ky(o)}),g=G(h,2),p=g[0],b=g[1];f.exports.useEffect(function(){var I=Ky(o);b(I!=null?I:null)});var m=r6(v&&!p),y=G(m,2),S=y[0],x=y[1],$=p!=null?p:S;s6(r&&n&&Rn()&&($===S||$===document.body));var E=null;if(l&&ki(l)&&t){var w=l;E=w.ref}var R=Fi(E,t);if(!v||!Rn()||p===void 0)return null;var P=$===!1||c6(),N=l;return t&&(N=f.exports.cloneElement(l,{ref:R})),C(Mw.Provider,{value:x,children:P?N:Gn.exports.createPortal(N,$)})}),Ow=f.exports.createContext({});function u6(){var e=U({},As);return e.useId}var qy=0,Xy=u6();const Rw=Xy?function(t){var n=Xy();return t||n}:function(t){var n=f.exports.useState("ssr-id"),r=G(n,2),o=r[0],i=r[1];return f.exports.useEffect(function(){var a=qy;qy+=1,i("rc_unique_".concat(a))},[]),t||o};function Qy(e,t,n){var r=t;return!r&&n&&(r="".concat(e,"-").concat(n)),r}function Zy(e,t){var n=e["page".concat(t?"Y":"X","Offset")],r="scroll".concat(t?"Top":"Left");if(typeof n!="number"){var o=e.document;n=o.documentElement[r],typeof n!="number"&&(n=o.body[r])}return n}function d6(e){var t=e.getBoundingClientRect(),n={left:t.left,top:t.top},r=e.ownerDocument,o=r.defaultView||r.parentWindow;return n.left+=Zy(o),n.top+=Zy(o,!0),n}const f6=f.exports.memo(function(e){var t=e.children;return t},function(e,t){var n=t.shouldUpdate;return!n});var Jy={width:0,height:0,overflow:"hidden",outline:"none"},v6=lt.forwardRef(function(e,t){var n=e.prefixCls,r=e.className,o=e.style,i=e.title,a=e.ariaId,l=e.footer,s=e.closable,c=e.closeIcon,u=e.onClose,d=e.children,v=e.bodyStyle,h=e.bodyProps,g=e.modalRender,p=e.onMouseDown,b=e.onMouseUp,m=e.holderRef,y=e.visible,S=e.forceRender,x=e.width,$=e.height,E=e.classNames,w=e.styles,R=lt.useContext(Ow),P=R.panel,N=Fi(m,P),I=f.exports.useRef(),z=f.exports.useRef();lt.useImperativeHandle(t,function(){return{focus:function(){var L;(L=I.current)===null||L===void 0||L.focus()},changeActive:function(L){var A=document,B=A.activeElement;L&&B===z.current?I.current.focus():!L&&B===I.current&&z.current.focus()}}});var F={};x!==void 0&&(F.width=x),$!==void 0&&(F.height=$);var T;l&&(T=C("div",{className:te("".concat(n,"-footer"),E==null?void 0:E.footer),style:U({},w==null?void 0:w.footer),children:l}));var D;i&&(D=C("div",{className:te("".concat(n,"-header"),E==null?void 0:E.header),style:U({},w==null?void 0:w.header),children:C("div",{className:"".concat(n,"-title"),id:a,children:i})}));var _;s&&(_=C("button",{type:"button",onClick:u,"aria-label":"Close",className:"".concat(n,"-close"),children:c||C("span",{className:"".concat(n,"-close-x")})}));var O=ie("div",{className:te("".concat(n,"-content"),E==null?void 0:E.content),style:w==null?void 0:w.content,children:[_,D,C("div",{className:te("".concat(n,"-body"),E==null?void 0:E.body),style:U(U({},v),w==null?void 0:w.body),...h,children:d}),T]});return ie("div",{role:"dialog","aria-labelledby":i?a:null,"aria-modal":"true",ref:N,style:U(U({},o),F),className:te(n,r),onMouseDown:p,onMouseUp:b,children:[C("div",{tabIndex:0,ref:I,style:Jy,"aria-hidden":"true"}),C(f6,{shouldUpdate:y||S,children:g?g(O):O}),C("div",{tabIndex:0,ref:z,style:Jy,"aria-hidden":"true"})]},"dialog-element")}),Iw=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.title,o=e.style,i=e.className,a=e.visible,l=e.forceRender,s=e.destroyOnClose,c=e.motionName,u=e.ariaId,d=e.onVisibleChanged,v=e.mousePosition,h=f.exports.useRef(),g=f.exports.useState(),p=G(g,2),b=p[0],m=p[1],y={};b&&(y.transformOrigin=b);function S(){var x=d6(h.current);m(v?"".concat(v.x-x.left,"px ").concat(v.y-x.top,"px"):"")}return C(to,{visible:a,onVisibleChanged:d,onAppearPrepare:S,onEnterPrepare:S,forceRender:l,motionName:c,removeOnLeave:s,ref:h,children:function(x,$){var E=x.className,w=x.style;return C(v6,{...e,ref:t,title:r,ariaId:u,prefixCls:n,holderRef:$,style:U(U(U({},w),o),y),className:te(i,E)})}})});Iw.displayName="Content";function p6(e){var t=e.prefixCls,n=e.style,r=e.visible,o=e.maskProps,i=e.motionName,a=e.className;return C(to,{visible:r,motionName:i,leavedClassName:"".concat(t,"-mask-hidden"),children:function(l,s){var c=l.className,u=l.style;return C("div",{ref:s,style:U(U({},u),n),className:te("".concat(t,"-mask"),c,a),...o})}},"mask")}function g6(e){var t=e.prefixCls,n=t===void 0?"rc-dialog":t,r=e.zIndex,o=e.visible,i=o===void 0?!1:o,a=e.keyboard,l=a===void 0?!0:a,s=e.focusTriggerAfterClose,c=s===void 0?!0:s,u=e.wrapStyle,d=e.wrapClassName,v=e.wrapProps,h=e.onClose,g=e.afterOpenChange,p=e.afterClose,b=e.transitionName,m=e.animation,y=e.closable,S=y===void 0?!0:y,x=e.mask,$=x===void 0?!0:x,E=e.maskTransitionName,w=e.maskAnimation,R=e.maskClosable,P=R===void 0?!0:R,N=e.maskStyle,I=e.maskProps,z=e.rootClassName,F=e.classNames,T=e.styles,D=f.exports.useRef(),_=f.exports.useRef(),O=f.exports.useRef(),M=f.exports.useState(i),L=G(M,2),A=L[0],B=L[1],k=Rw();function j(){Np(_.current,document.activeElement)||(D.current=document.activeElement)}function H(){if(!Np(_.current,document.activeElement)){var ae;(ae=O.current)===null||ae===void 0||ae.focus()}}function W(ae){if(ae)H();else{if(B(!1),$&&D.current&&c){try{D.current.focus({preventScroll:!0})}catch{}D.current=null}A&&(p==null||p())}g==null||g(ae)}function Y(ae){h==null||h(ae)}var K=f.exports.useRef(!1),q=f.exports.useRef(),ee=function(){clearTimeout(q.current),K.current=!0},Z=function(){q.current=setTimeout(function(){K.current=!1})},Q=null;P&&(Q=function(J){K.current?K.current=!1:_.current===J.target&&Y(J)});function ne(ae){if(l&&ae.keyCode===ue.ESC){ae.stopPropagation(),Y(ae);return}i&&ae.keyCode===ue.TAB&&O.current.changeActive(!ae.shiftKey)}return f.exports.useEffect(function(){i&&(B(!0),j())},[i]),f.exports.useEffect(function(){return function(){clearTimeout(q.current)}},[]),ie("div",{className:te("".concat(n,"-root"),z),...Ka(e,{data:!0}),children:[C(p6,{prefixCls:n,visible:$&&i,motionName:Qy(n,E,w),style:U(U({zIndex:r},N),T==null?void 0:T.mask),maskProps:I,className:F==null?void 0:F.mask}),C("div",{tabIndex:-1,onKeyDown:ne,className:te("".concat(n,"-wrap"),d,F==null?void 0:F.wrapper),ref:_,onClick:Q,style:U(U(U({zIndex:r},u),T==null?void 0:T.wrapper),{},{display:A?null:"none"}),...v,children:C(Iw,{...e,onMouseDown:ee,onMouseUp:Z,ref:O,closable:S,ariaId:k,prefixCls:n,visible:i&&A,onClose:Y,onVisibleChanged:W,motionName:Qy(n,b,m)})})]})}var Pw=function(t){var n=t.visible,r=t.getContainer,o=t.forceRender,i=t.destroyOnClose,a=i===void 0?!1:i,l=t.afterClose,s=t.panelRef,c=f.exports.useState(n),u=G(c,2),d=u[0],v=u[1],h=f.exports.useMemo(function(){return{panel:s}},[s]);return f.exports.useEffect(function(){n&&v(!0)},[n]),!o&&a&&!d?null:C(Ow.Provider,{value:h,children:C(nf,{open:n||o||d,autoDestroy:!1,getContainer:r,autoLock:n||d,children:C(g6,{...t,destroyOnClose:a,afterClose:function(){l==null||l(),v(!1)}})})})};Pw.displayName="Dialog";function h6(e,t,n){return typeof e=="boolean"?e:t===void 0?!!n:t!==!1&&t!==null}function m6(e,t,n){let r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:C(eo,{}),o=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1;if(!h6(e,t,o))return[!1,null];const a=typeof t=="boolean"||t===void 0||t===null?r:t;return[!0,n?n(a):a]}var Si="RC_FORM_INTERNAL_HOOKS",Pt=function(){Mn(!1,"Can not find FormContext. Please make sure you wrap Field under Form.")},qa=f.exports.createContext({getFieldValue:Pt,getFieldsValue:Pt,getFieldError:Pt,getFieldWarning:Pt,getFieldsError:Pt,isFieldsTouched:Pt,isFieldTouched:Pt,isFieldValidating:Pt,isFieldsValidating:Pt,resetFields:Pt,setFields:Pt,setFieldValue:Pt,setFieldsValue:Pt,validateFields:Pt,submit:Pt,getInternalHooks:function(){return Pt(),{dispatch:Pt,initEntityValue:Pt,registerField:Pt,useSubscribe:Pt,setInitialValues:Pt,destroyForm:Pt,setCallbacks:Pt,registerWatch:Pt,getFields:Pt,setValidateMessages:Pt,setPreserve:Pt,getInitialValue:Pt}}}),Qu=f.exports.createContext(null);function lg(e){return e==null?[]:Array.isArray(e)?e:[e]}function y6(e){return e&&!!e._init}function Ci(){return Ci=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function iu(e,t,n){return S6()?iu=Reflect.construct.bind():iu=function(o,i,a){var l=[null];l.push.apply(l,i);var s=Function.bind.apply(o,l),c=new s;return a&&Os(c,a.prototype),c},iu.apply(null,arguments)}function C6(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function cg(e){var t=typeof Map=="function"?new Map:void 0;return cg=function(r){if(r===null||!C6(r))return r;if(typeof r!="function")throw new TypeError("Super expression must either be null or a function");if(typeof t<"u"){if(t.has(r))return t.get(r);t.set(r,o)}function o(){return iu(r,arguments,sg(this).constructor)}return o.prototype=Object.create(r.prototype,{constructor:{value:o,enumerable:!1,writable:!0,configurable:!0}}),Os(o,r)},cg(e)}var x6=/%[sdj%]/g,w6=function(){};typeof process<"u"&&process.env;function ug(e){if(!e||!e.length)return null;var t={};return e.forEach(function(n){var r=n.field;t[r]=t[r]||[],t[r].push(n)}),t}function nr(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r=i)return l;switch(l){case"%s":return String(n[o++]);case"%d":return Number(n[o++]);case"%j":try{return JSON.stringify(n[o++])}catch{return"[Circular]"}break;default:return l}});return a}return e}function $6(e){return e==="string"||e==="url"||e==="hex"||e==="email"||e==="date"||e==="pattern"}function ln(e,t){return!!(e==null||t==="array"&&Array.isArray(e)&&!e.length||$6(t)&&typeof e=="string"&&!e)}function E6(e,t,n){var r=[],o=0,i=e.length;function a(l){r.push.apply(r,l||[]),o++,o===i&&n(r)}e.forEach(function(l){t(l,a)})}function eb(e,t,n){var r=0,o=e.length;function i(a){if(a&&a.length){n(a);return}var l=r;r=r+1,l()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/,hex:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i},Nl={integer:function(t){return Nl.number(t)&&parseInt(t,10)===t},float:function(t){return Nl.number(t)&&!Nl.integer(t)},array:function(t){return Array.isArray(t)},regexp:function(t){if(t instanceof RegExp)return!0;try{return!!new RegExp(t)}catch{return!1}},date:function(t){return typeof t.getTime=="function"&&typeof t.getMonth=="function"&&typeof t.getYear=="function"&&!isNaN(t.getTime())},number:function(t){return isNaN(t)?!1:typeof t=="number"},object:function(t){return typeof t=="object"&&!Nl.array(t)},method:function(t){return typeof t=="function"},email:function(t){return typeof t=="string"&&t.length<=320&&!!t.match(ob.email)},url:function(t){return typeof t=="string"&&t.length<=2048&&!!t.match(T6())},hex:function(t){return typeof t=="string"&&!!t.match(ob.hex)}},N6=function(t,n,r,o,i){if(t.required&&n===void 0){Tw(t,n,r,o,i);return}var a=["integer","float","array","regexp","object","method","email","number","date","url","hex"],l=t.type;a.indexOf(l)>-1?Nl[l](n)||o.push(nr(i.messages.types[l],t.fullField,t.type)):l&&typeof n!==t.type&&o.push(nr(i.messages.types[l],t.fullField,t.type))},_6=function(t,n,r,o,i){var a=typeof t.len=="number",l=typeof t.min=="number",s=typeof t.max=="number",c=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,u=n,d=null,v=typeof n=="number",h=typeof n=="string",g=Array.isArray(n);if(v?d="number":h?d="string":g&&(d="array"),!d)return!1;g&&(u=n.length),h&&(u=n.replace(c,"_").length),a?u!==t.len&&o.push(nr(i.messages[d].len,t.fullField,t.len)):l&&!s&&ut.max?o.push(nr(i.messages[d].max,t.fullField,t.max)):l&&s&&(ut.max)&&o.push(nr(i.messages[d].range,t.fullField,t.min,t.max))},Gi="enum",A6=function(t,n,r,o,i){t[Gi]=Array.isArray(t[Gi])?t[Gi]:[],t[Gi].indexOf(n)===-1&&o.push(nr(i.messages[Gi],t.fullField,t[Gi].join(", ")))},D6=function(t,n,r,o,i){if(t.pattern){if(t.pattern instanceof RegExp)t.pattern.lastIndex=0,t.pattern.test(n)||o.push(nr(i.messages.pattern.mismatch,t.fullField,n,t.pattern));else if(typeof t.pattern=="string"){var a=new RegExp(t.pattern);a.test(n)||o.push(nr(i.messages.pattern.mismatch,t.fullField,n,t.pattern))}}},pt={required:Tw,whitespace:P6,type:N6,range:_6,enum:A6,pattern:D6},L6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n,"string")&&!t.required)return r();pt.required(t,n,o,a,i,"string"),ln(n,"string")||(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i),pt.pattern(t,n,o,a,i),t.whitespace===!0&&pt.whitespace(t,n,o,a,i))}r(a)},z6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt.type(t,n,o,a,i)}r(a)},F6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(n===""&&(n=void 0),ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},k6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt.type(t,n,o,a,i)}r(a)},B6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),ln(n)||pt.type(t,n,o,a,i)}r(a)},j6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},H6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},W6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(n==null&&!t.required)return r();pt.required(t,n,o,a,i,"array"),n!=null&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},V6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt.type(t,n,o,a,i)}r(a)},U6="enum",Y6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt[U6](t,n,o,a,i)}r(a)},G6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n,"string")&&!t.required)return r();pt.required(t,n,o,a,i),ln(n,"string")||pt.pattern(t,n,o,a,i)}r(a)},K6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n,"date")&&!t.required)return r();if(pt.required(t,n,o,a,i),!ln(n,"date")){var s;n instanceof Date?s=n:s=new Date(n),pt.type(t,s,o,a,i),s&&pt.range(t,s.getTime(),o,a,i)}}r(a)},q6=function(t,n,r,o,i){var a=[],l=Array.isArray(n)?"array":typeof n;pt.required(t,n,o,a,i,l),r(a)},vv=function(t,n,r,o,i){var a=t.type,l=[],s=t.required||!t.required&&o.hasOwnProperty(t.field);if(s){if(ln(n,a)&&!t.required)return r();pt.required(t,n,o,l,i,a),ln(n,a)||pt.type(t,n,o,l,i)}r(l)},X6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i)}r(a)},Zl={string:L6,method:z6,number:F6,boolean:k6,regexp:B6,integer:j6,float:H6,array:W6,object:V6,enum:Y6,pattern:G6,date:K6,url:vv,hex:vv,email:vv,required:q6,any:X6};function dg(){return{default:"Validation error on field %s",required:"%s is required",enum:"%s must be one of %s",whitespace:"%s cannot be empty",date:{format:"%s date %s is invalid for format %s",parse:"%s date could not be parsed, %s is invalid ",invalid:"%s date %s is invalid"},types:{string:"%s is not a %s",method:"%s is not a %s (function)",array:"%s is not an %s",object:"%s is not an %s",number:"%s is not a %s",date:"%s is not a %s",boolean:"%s is not a %s",integer:"%s is not an %s",float:"%s is not a %s",regexp:"%s is not a valid %s",email:"%s is not a valid %s",url:"%s is not a valid %s",hex:"%s is not a valid %s"},string:{len:"%s must be exactly %s characters",min:"%s must be at least %s characters",max:"%s cannot be longer than %s characters",range:"%s must be between %s and %s characters"},number:{len:"%s must equal %s",min:"%s cannot be less than %s",max:"%s cannot be greater than %s",range:"%s must be between %s and %s"},array:{len:"%s must be exactly %s in length",min:"%s cannot be less than %s in length",max:"%s cannot be greater than %s in length",range:"%s must be between %s and %s in length"},pattern:{mismatch:"%s value %s does not match pattern %s"},clone:function(){var t=JSON.parse(JSON.stringify(this));return t.clone=this.clone,t}}}var fg=dg(),Gs=function(){function e(n){this.rules=null,this._messages=fg,this.define(n)}var t=e.prototype;return t.define=function(r){var o=this;if(!r)throw new Error("Cannot configure a schema with no rules");if(typeof r!="object"||Array.isArray(r))throw new Error("Rules must be an object");this.rules={},Object.keys(r).forEach(function(i){var a=r[i];o.rules[i]=Array.isArray(a)?a:[a]})},t.messages=function(r){return r&&(this._messages=rb(dg(),r)),this._messages},t.validate=function(r,o,i){var a=this;o===void 0&&(o={}),i===void 0&&(i=function(){});var l=r,s=o,c=i;if(typeof s=="function"&&(c=s,s={}),!this.rules||Object.keys(this.rules).length===0)return c&&c(null,l),Promise.resolve(l);function u(p){var b=[],m={};function y(x){if(Array.isArray(x)){var $;b=($=b).concat.apply($,x)}else b.push(x)}for(var S=0;S2&&arguments[2]!==void 0?arguments[2]:!1;return e&&e.some(function(r){return _w(t,r,n)})}function _w(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1;return!e||!t||!n&&e.length!==t.length?!1:t.every(function(r,o){return e[o]===r})}function t_(e,t){if(e===t)return!0;if(!e&&t||e&&!t||!e||!t||Qe(e)!=="object"||Qe(t)!=="object")return!1;var n=Object.keys(e),r=Object.keys(t),o=new Set([].concat(n,r));return Oe(o).every(function(i){var a=e[i],l=t[i];return typeof a=="function"&&typeof l=="function"?!0:a===l})}function n_(e){var t=arguments.length<=1?void 0:arguments[1];return t&&t.target&&Qe(t.target)==="object"&&e in t.target?t.target[e]:t}function sb(e,t,n){var r=e.length;if(t<0||t>=r||n<0||n>=r)return e;var o=e[t],i=t-n;return i>0?[].concat(Oe(e.slice(0,n)),[o],Oe(e.slice(n,t)),Oe(e.slice(t+1,r))):i<0?[].concat(Oe(e.slice(0,t)),Oe(e.slice(t+1,n+1)),[o],Oe(e.slice(n+1,r))):e}var r_=["name"],cr=[];function cb(e,t,n,r,o,i){return typeof e=="function"?e(t,n,"source"in i?{source:i.source}:{}):r!==o}var tm=function(e){Bi(n,e);var t=Ws(n);function n(r){var o;if(zn(this,n),o=t.call(this,r),V(xt(o),"state",{resetCount:0}),V(xt(o),"cancelRegisterFunc",null),V(xt(o),"mounted",!1),V(xt(o),"touched",!1),V(xt(o),"dirty",!1),V(xt(o),"validatePromise",void 0),V(xt(o),"prevValidating",void 0),V(xt(o),"errors",cr),V(xt(o),"warnings",cr),V(xt(o),"cancelRegister",function(){var s=o.props,c=s.preserve,u=s.isListField,d=s.name;o.cancelRegisterFunc&&o.cancelRegisterFunc(u,c,qt(d)),o.cancelRegisterFunc=null}),V(xt(o),"getNamePath",function(){var s=o.props,c=s.name,u=s.fieldContext,d=u.prefixName,v=d===void 0?[]:d;return c!==void 0?[].concat(Oe(v),Oe(c)):[]}),V(xt(o),"getRules",function(){var s=o.props,c=s.rules,u=c===void 0?[]:c,d=s.fieldContext;return u.map(function(v){return typeof v=="function"?v(d):v})}),V(xt(o),"refresh",function(){!o.mounted||o.setState(function(s){var c=s.resetCount;return{resetCount:c+1}})}),V(xt(o),"metaCache",null),V(xt(o),"triggerMetaEvent",function(s){var c=o.props.onMetaChange;if(c){var u=U(U({},o.getMeta()),{},{destroy:s});Vs(o.metaCache,u)||c(u),o.metaCache=u}else o.metaCache=null}),V(xt(o),"onStoreChange",function(s,c,u){var d=o.props,v=d.shouldUpdate,h=d.dependencies,g=h===void 0?[]:h,p=d.onReset,b=u.store,m=o.getNamePath(),y=o.getValue(s),S=o.getValue(b),x=c&&Aa(c,m);switch(u.type==="valueUpdate"&&u.source==="external"&&y!==S&&(o.touched=!0,o.dirty=!0,o.validatePromise=null,o.errors=cr,o.warnings=cr,o.triggerMetaEvent()),u.type){case"reset":if(!c||x){o.touched=!1,o.dirty=!1,o.validatePromise=void 0,o.errors=cr,o.warnings=cr,o.triggerMetaEvent(),p==null||p(),o.refresh();return}break;case"remove":{if(v){o.reRender();return}break}case"setField":{var $=u.data;if(x){"touched"in $&&(o.touched=$.touched),"validating"in $&&!("originRCField"in $)&&(o.validatePromise=$.validating?Promise.resolve([]):null),"errors"in $&&(o.errors=$.errors||cr),"warnings"in $&&(o.warnings=$.warnings||cr),o.dirty=!0,o.triggerMetaEvent(),o.reRender();return}else if("value"in $&&Aa(c,m,!0)){o.reRender();return}if(v&&!m.length&&cb(v,s,b,y,S,u)){o.reRender();return}break}case"dependenciesUpdate":{var E=g.map(qt);if(E.some(function(w){return Aa(u.relatedFields,w)})){o.reRender();return}break}default:if(x||(!g.length||m.length||v)&&cb(v,s,b,y,S,u)){o.reRender();return}break}v===!0&&o.reRender()}),V(xt(o),"validateRules",function(s){var c=o.getNamePath(),u=o.getValue(),d=s||{},v=d.triggerName,h=d.validateOnly,g=h===void 0?!1:h,p=Promise.resolve().then(ji(An().mark(function b(){var m,y,S,x,$,E,w;return An().wrap(function(P){for(;;)switch(P.prev=P.next){case 0:if(o.mounted){P.next=2;break}return P.abrupt("return",[]);case 2:if(m=o.props,y=m.validateFirst,S=y===void 0?!1:y,x=m.messageVariables,$=m.validateDebounce,E=o.getRules(),v&&(E=E.filter(function(N){return N}).filter(function(N){var I=N.validateTrigger;if(!I)return!0;var z=lg(I);return z.includes(v)})),!($&&v)){P.next=10;break}return P.next=8,new Promise(function(N){setTimeout(N,$)});case 8:if(o.validatePromise===p){P.next=10;break}return P.abrupt("return",[]);case 10:return w=Z6(c,u,E,s,S,x),w.catch(function(N){return N}).then(function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:cr;if(o.validatePromise===p){var I;o.validatePromise=null;var z=[],F=[];(I=N.forEach)===null||I===void 0||I.call(N,function(T){var D=T.rule.warningOnly,_=T.errors,O=_===void 0?cr:_;D?F.push.apply(F,Oe(O)):z.push.apply(z,Oe(O))}),o.errors=z,o.warnings=F,o.triggerMetaEvent(),o.reRender()}}),P.abrupt("return",w);case 13:case"end":return P.stop()}},b)})));return g||(o.validatePromise=p,o.dirty=!0,o.errors=cr,o.warnings=cr,o.triggerMetaEvent(),o.reRender()),p}),V(xt(o),"isFieldValidating",function(){return!!o.validatePromise}),V(xt(o),"isFieldTouched",function(){return o.touched}),V(xt(o),"isFieldDirty",function(){if(o.dirty||o.props.initialValue!==void 0)return!0;var s=o.props.fieldContext,c=s.getInternalHooks(Si),u=c.getInitialValue;return u(o.getNamePath())!==void 0}),V(xt(o),"getErrors",function(){return o.errors}),V(xt(o),"getWarnings",function(){return o.warnings}),V(xt(o),"isListField",function(){return o.props.isListField}),V(xt(o),"isList",function(){return o.props.isList}),V(xt(o),"isPreserve",function(){return o.props.preserve}),V(xt(o),"getMeta",function(){o.prevValidating=o.isFieldValidating();var s={touched:o.isFieldTouched(),validating:o.prevValidating,errors:o.errors,warnings:o.warnings,name:o.getNamePath(),validated:o.validatePromise===null};return s}),V(xt(o),"getOnlyChild",function(s){if(typeof s=="function"){var c=o.getMeta();return U(U({},o.getOnlyChild(s(o.getControlled(),c,o.props.fieldContext))),{},{isFunction:!0})}var u=Qo(s);return u.length!==1||!f.exports.isValidElement(u[0])?{child:u,isFunction:!1}:{child:u[0],isFunction:!1}}),V(xt(o),"getValue",function(s){var c=o.props.fieldContext.getFieldsValue,u=o.getNamePath();return qr(s||c(!0),u)}),V(xt(o),"getControlled",function(){var s=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},c=o.props,u=c.trigger,d=c.validateTrigger,v=c.getValueFromEvent,h=c.normalize,g=c.valuePropName,p=c.getValueProps,b=c.fieldContext,m=d!==void 0?d:b.validateTrigger,y=o.getNamePath(),S=b.getInternalHooks,x=b.getFieldsValue,$=S(Si),E=$.dispatch,w=o.getValue(),R=p||function(z){return V({},g,z)},P=s[u],N=U(U({},s),R(w));N[u]=function(){o.touched=!0,o.dirty=!0,o.triggerMetaEvent();for(var z,F=arguments.length,T=new Array(F),D=0;D=0&&N<=I.length?(u.keys=[].concat(Oe(u.keys.slice(0,N)),[u.id],Oe(u.keys.slice(N))),S([].concat(Oe(I.slice(0,N)),[P],Oe(I.slice(N))))):(u.keys=[].concat(Oe(u.keys),[u.id]),S([].concat(Oe(I),[P]))),u.id+=1},remove:function(P){var N=$(),I=new Set(Array.isArray(P)?P:[P]);I.size<=0||(u.keys=u.keys.filter(function(z,F){return!I.has(F)}),S(N.filter(function(z,F){return!I.has(F)})))},move:function(P,N){if(P!==N){var I=$();P<0||P>=I.length||N<0||N>=I.length||(u.keys=sb(u.keys,P,N),S(sb(I,P,N)))}}},w=y||[];return Array.isArray(w)||(w=[]),r(w.map(function(R,P){var N=u.keys[P];return N===void 0&&(u.keys[P]=u.id,N=u.keys[P],u.id+=1),{name:P,key:N,isListField:!0}}),E,b)}})})})}function i_(e){var t=!1,n=e.length,r=[];return e.length?new Promise(function(o,i){e.forEach(function(a,l){a.catch(function(s){return t=!0,s}).then(function(s){n-=1,r[l]=s,!(n>0)&&(t&&i(r),o(r))})})}):Promise.resolve([])}var Dw="__@field_split__";function pv(e){return e.map(function(t){return"".concat(Qe(t),":").concat(t)}).join(Dw)}var Ki=function(){function e(){zn(this,e),V(this,"kvs",new Map)}return Fn(e,[{key:"set",value:function(n,r){this.kvs.set(pv(n),r)}},{key:"get",value:function(n){return this.kvs.get(pv(n))}},{key:"update",value:function(n,r){var o=this.get(n),i=r(o);i?this.set(n,i):this.delete(n)}},{key:"delete",value:function(n){this.kvs.delete(pv(n))}},{key:"map",value:function(n){return Oe(this.kvs.entries()).map(function(r){var o=G(r,2),i=o[0],a=o[1],l=i.split(Dw);return n({key:l.map(function(s){var c=s.match(/^([^:]*):(.*)$/),u=G(c,3),d=u[1],v=u[2];return d==="number"?Number(v):v}),value:a})})}},{key:"toJSON",value:function(){var n={};return this.map(function(r){var o=r.key,i=r.value;return n[o.join(".")]=i,null}),n}}]),e}(),a_=["name"],l_=Fn(function e(t){var n=this;zn(this,e),V(this,"formHooked",!1),V(this,"forceRootUpdate",void 0),V(this,"subscribable",!0),V(this,"store",{}),V(this,"fieldEntities",[]),V(this,"initialValues",{}),V(this,"callbacks",{}),V(this,"validateMessages",null),V(this,"preserve",null),V(this,"lastValidatePromise",null),V(this,"getForm",function(){return{getFieldValue:n.getFieldValue,getFieldsValue:n.getFieldsValue,getFieldError:n.getFieldError,getFieldWarning:n.getFieldWarning,getFieldsError:n.getFieldsError,isFieldsTouched:n.isFieldsTouched,isFieldTouched:n.isFieldTouched,isFieldValidating:n.isFieldValidating,isFieldsValidating:n.isFieldsValidating,resetFields:n.resetFields,setFields:n.setFields,setFieldValue:n.setFieldValue,setFieldsValue:n.setFieldsValue,validateFields:n.validateFields,submit:n.submit,_init:!0,getInternalHooks:n.getInternalHooks}}),V(this,"getInternalHooks",function(r){return r===Si?(n.formHooked=!0,{dispatch:n.dispatch,initEntityValue:n.initEntityValue,registerField:n.registerField,useSubscribe:n.useSubscribe,setInitialValues:n.setInitialValues,destroyForm:n.destroyForm,setCallbacks:n.setCallbacks,setValidateMessages:n.setValidateMessages,getFields:n.getFields,setPreserve:n.setPreserve,getInitialValue:n.getInitialValue,registerWatch:n.registerWatch}):(Mn(!1,"`getInternalHooks` is internal usage. Should not call directly."),null)}),V(this,"useSubscribe",function(r){n.subscribable=r}),V(this,"prevWithoutPreserves",null),V(this,"setInitialValues",function(r,o){if(n.initialValues=r||{},o){var i,a=Ca(r,n.store);(i=n.prevWithoutPreserves)===null||i===void 0||i.map(function(l){var s=l.key;a=Tr(a,s,qr(r,s))}),n.prevWithoutPreserves=null,n.updateStore(a)}}),V(this,"destroyForm",function(){var r=new Ki;n.getFieldEntities(!0).forEach(function(o){n.isMergedPreserve(o.isPreserve())||r.set(o.getNamePath(),!0)}),n.prevWithoutPreserves=r}),V(this,"getInitialValue",function(r){var o=qr(n.initialValues,r);return r.length?Ca(o):o}),V(this,"setCallbacks",function(r){n.callbacks=r}),V(this,"setValidateMessages",function(r){n.validateMessages=r}),V(this,"setPreserve",function(r){n.preserve=r}),V(this,"watchList",[]),V(this,"registerWatch",function(r){return n.watchList.push(r),function(){n.watchList=n.watchList.filter(function(o){return o!==r})}}),V(this,"notifyWatch",function(){var r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[];if(n.watchList.length){var o=n.getFieldsValue(),i=n.getFieldsValue(!0);n.watchList.forEach(function(a){a(o,i,r)})}}),V(this,"timeoutId",null),V(this,"warningUnhooked",function(){}),V(this,"updateStore",function(r){n.store=r}),V(this,"getFieldEntities",function(){var r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1;return r?n.fieldEntities.filter(function(o){return o.getNamePath().length}):n.fieldEntities}),V(this,"getFieldsMap",function(){var r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,o=new Ki;return n.getFieldEntities(r).forEach(function(i){var a=i.getNamePath();o.set(a,i)}),o}),V(this,"getFieldEntitiesForNamePathList",function(r){if(!r)return n.getFieldEntities(!0);var o=n.getFieldsMap(!0);return r.map(function(i){var a=qt(i);return o.get(a)||{INVALIDATE_NAME_PATH:qt(i)}})}),V(this,"getFieldsValue",function(r,o){n.warningUnhooked();var i,a,l;if(r===!0||Array.isArray(r)?(i=r,a=o):r&&Qe(r)==="object"&&(l=r.strict,a=r.filter),i===!0&&!a)return n.store;var s=n.getFieldEntitiesForNamePathList(Array.isArray(i)?i:null),c=[];return s.forEach(function(u){var d,v,h="INVALIDATE_NAME_PATH"in u?u.INVALIDATE_NAME_PATH:u.getNamePath();if(l){var g,p;if((g=(p=u).isList)!==null&&g!==void 0&&g.call(p))return}else if(!i&&(d=(v=u).isListField)!==null&&d!==void 0&&d.call(v))return;if(!a)c.push(h);else{var b="getMeta"in u?u.getMeta():null;a(b)&&c.push(h)}}),lb(n.store,c.map(qt))}),V(this,"getFieldValue",function(r){n.warningUnhooked();var o=qt(r);return qr(n.store,o)}),V(this,"getFieldsError",function(r){n.warningUnhooked();var o=n.getFieldEntitiesForNamePathList(r);return o.map(function(i,a){return i&&!("INVALIDATE_NAME_PATH"in i)?{name:i.getNamePath(),errors:i.getErrors(),warnings:i.getWarnings()}:{name:qt(r[a]),errors:[],warnings:[]}})}),V(this,"getFieldError",function(r){n.warningUnhooked();var o=qt(r),i=n.getFieldsError([o])[0];return i.errors}),V(this,"getFieldWarning",function(r){n.warningUnhooked();var o=qt(r),i=n.getFieldsError([o])[0];return i.warnings}),V(this,"isFieldsTouched",function(){n.warningUnhooked();for(var r=arguments.length,o=new Array(r),i=0;i0&&arguments[0]!==void 0?arguments[0]:{},o=new Ki,i=n.getFieldEntities(!0);i.forEach(function(s){var c=s.props.initialValue,u=s.getNamePath();if(c!==void 0){var d=o.get(u)||new Set;d.add({entity:s,value:c}),o.set(u,d)}});var a=function(c){c.forEach(function(u){var d=u.props.initialValue;if(d!==void 0){var v=u.getNamePath(),h=n.getInitialValue(v);if(h!==void 0)Mn(!1,"Form already set 'initialValues' with path '".concat(v.join("."),"'. Field can not overwrite it."));else{var g=o.get(v);if(g&&g.size>1)Mn(!1,"Multiple Field with path '".concat(v.join("."),"' set 'initialValue'. Can not decide which one to pick."));else if(g){var p=n.getFieldValue(v),b=u.isListField();!b&&(!r.skipExist||p===void 0)&&n.updateStore(Tr(n.store,v,Oe(g)[0].value))}}}})},l;r.entities?l=r.entities:r.namePathList?(l=[],r.namePathList.forEach(function(s){var c=o.get(s);if(c){var u;(u=l).push.apply(u,Oe(Oe(c).map(function(d){return d.entity})))}})):l=i,a(l)}),V(this,"resetFields",function(r){n.warningUnhooked();var o=n.store;if(!r){n.updateStore(Ca(n.initialValues)),n.resetWithFieldInitialValue(),n.notifyObservers(o,null,{type:"reset"}),n.notifyWatch();return}var i=r.map(qt);i.forEach(function(a){var l=n.getInitialValue(a);n.updateStore(Tr(n.store,a,l))}),n.resetWithFieldInitialValue({namePathList:i}),n.notifyObservers(o,i,{type:"reset"}),n.notifyWatch(i)}),V(this,"setFields",function(r){n.warningUnhooked();var o=n.store,i=[];r.forEach(function(a){var l=a.name,s=Je(a,a_),c=qt(l);i.push(c),"value"in s&&n.updateStore(Tr(n.store,c,s.value)),n.notifyObservers(o,[c],{type:"setField",data:a})}),n.notifyWatch(i)}),V(this,"getFields",function(){var r=n.getFieldEntities(!0),o=r.map(function(i){var a=i.getNamePath(),l=i.getMeta(),s=U(U({},l),{},{name:a,value:n.getFieldValue(a)});return Object.defineProperty(s,"originRCField",{value:!0}),s});return o}),V(this,"initEntityValue",function(r){var o=r.props.initialValue;if(o!==void 0){var i=r.getNamePath(),a=qr(n.store,i);a===void 0&&n.updateStore(Tr(n.store,i,o))}}),V(this,"isMergedPreserve",function(r){var o=r!==void 0?r:n.preserve;return o!=null?o:!0}),V(this,"registerField",function(r){n.fieldEntities.push(r);var o=r.getNamePath();if(n.notifyWatch([o]),r.props.initialValue!==void 0){var i=n.store;n.resetWithFieldInitialValue({entities:[r],skipExist:!0}),n.notifyObservers(i,[r.getNamePath()],{type:"valueUpdate",source:"internal"})}return function(a,l){var s=arguments.length>2&&arguments[2]!==void 0?arguments[2]:[];if(n.fieldEntities=n.fieldEntities.filter(function(d){return d!==r}),!n.isMergedPreserve(l)&&(!a||s.length>1)){var c=a?void 0:n.getInitialValue(o);if(o.length&&n.getFieldValue(o)!==c&&n.fieldEntities.every(function(d){return!_w(d.getNamePath(),o)})){var u=n.store;n.updateStore(Tr(u,o,c,!0)),n.notifyObservers(u,[o],{type:"remove"}),n.triggerDependenciesUpdate(u,o)}}n.notifyWatch([o])}}),V(this,"dispatch",function(r){switch(r.type){case"updateValue":{var o=r.namePath,i=r.value;n.updateValue(o,i);break}case"validateField":{var a=r.namePath,l=r.triggerName;n.validateFields([a],{triggerName:l});break}}}),V(this,"notifyObservers",function(r,o,i){if(n.subscribable){var a=U(U({},i),{},{store:n.getFieldsValue(!0)});n.getFieldEntities().forEach(function(l){var s=l.onStoreChange;s(r,o,a)})}else n.forceRootUpdate()}),V(this,"triggerDependenciesUpdate",function(r,o){var i=n.getDependencyChildrenFields(o);return i.length&&n.validateFields(i),n.notifyObservers(r,i,{type:"dependenciesUpdate",relatedFields:[o].concat(Oe(i))}),i}),V(this,"updateValue",function(r,o){var i=qt(r),a=n.store;n.updateStore(Tr(n.store,i,o)),n.notifyObservers(a,[i],{type:"valueUpdate",source:"internal"}),n.notifyWatch([i]);var l=n.triggerDependenciesUpdate(a,i),s=n.callbacks.onValuesChange;if(s){var c=lb(n.store,[i]);s(c,n.getFieldsValue())}n.triggerOnFieldsChange([i].concat(Oe(l)))}),V(this,"setFieldsValue",function(r){n.warningUnhooked();var o=n.store;if(r){var i=Ca(n.store,r);n.updateStore(i)}n.notifyObservers(o,null,{type:"valueUpdate",source:"external"}),n.notifyWatch()}),V(this,"setFieldValue",function(r,o){n.setFields([{name:r,value:o}])}),V(this,"getDependencyChildrenFields",function(r){var o=new Set,i=[],a=new Ki;n.getFieldEntities().forEach(function(s){var c=s.props.dependencies;(c||[]).forEach(function(u){var d=qt(u);a.update(d,function(){var v=arguments.length>0&&arguments[0]!==void 0?arguments[0]:new Set;return v.add(s),v})})});var l=function s(c){var u=a.get(c)||new Set;u.forEach(function(d){if(!o.has(d)){o.add(d);var v=d.getNamePath();d.isFieldDirty()&&v.length&&(i.push(v),s(v))}})};return l(r),i}),V(this,"triggerOnFieldsChange",function(r,o){var i=n.callbacks.onFieldsChange;if(i){var a=n.getFields();if(o){var l=new Ki;o.forEach(function(c){var u=c.name,d=c.errors;l.set(u,d)}),a.forEach(function(c){c.errors=l.get(c.name)||c.errors})}var s=a.filter(function(c){var u=c.name;return Aa(r,u)});s.length&&i(s,a)}}),V(this,"validateFields",function(r,o){n.warningUnhooked();var i,a;Array.isArray(r)||typeof r=="string"||typeof o=="string"?(i=r,a=o):a=r;var l=!!i,s=l?i.map(qt):[],c=[],u=String(Date.now()),d=new Set,v=a||{},h=v.recursive,g=v.dirty;n.getFieldEntities(!0).forEach(function(y){if(l||s.push(y.getNamePath()),!(!y.props.rules||!y.props.rules.length)&&!(g&&!y.isFieldDirty())){var S=y.getNamePath();if(d.add(S.join(u)),!l||Aa(s,S,h)){var x=y.validateRules(U({validateMessages:U(U({},Nw),n.validateMessages)},a));c.push(x.then(function(){return{name:S,errors:[],warnings:[]}}).catch(function($){var E,w=[],R=[];return(E=$.forEach)===null||E===void 0||E.call($,function(P){var N=P.rule.warningOnly,I=P.errors;N?R.push.apply(R,Oe(I)):w.push.apply(w,Oe(I))}),w.length?Promise.reject({name:S,errors:w,warnings:R}):{name:S,errors:w,warnings:R}}))}}});var p=i_(c);n.lastValidatePromise=p,p.catch(function(y){return y}).then(function(y){var S=y.map(function(x){var $=x.name;return $});n.notifyObservers(n.store,S,{type:"validateFinish"}),n.triggerOnFieldsChange(S,y)});var b=p.then(function(){return n.lastValidatePromise===p?Promise.resolve(n.getFieldsValue(s)):Promise.reject([])}).catch(function(y){var S=y.filter(function(x){return x&&x.errors.length});return Promise.reject({values:n.getFieldsValue(s),errorFields:S,outOfDate:n.lastValidatePromise!==p})});b.catch(function(y){return y});var m=s.filter(function(y){return d.has(y.join(u))});return n.triggerOnFieldsChange(m),b}),V(this,"submit",function(){n.warningUnhooked(),n.validateFields().then(function(r){var o=n.callbacks.onFinish;if(o)try{o(r)}catch(i){console.error(i)}}).catch(function(r){var o=n.callbacks.onFinishFailed;o&&o(r)})}),this.forceRootUpdate=t});function Lw(e){var t=f.exports.useRef(),n=f.exports.useState({}),r=G(n,2),o=r[1];if(!t.current)if(e)t.current=e;else{var i=function(){o({})},a=new l_(i);t.current=a.getForm()}return[t.current]}var mg=f.exports.createContext({triggerFormChange:function(){},triggerFormFinish:function(){},registerForm:function(){},unregisterForm:function(){}}),s_=function(t){var n=t.validateMessages,r=t.onFormChange,o=t.onFormFinish,i=t.children,a=f.exports.useContext(mg),l=f.exports.useRef({});return C(mg.Provider,{value:U(U({},a),{},{validateMessages:U(U({},a.validateMessages),n),triggerFormChange:function(c,u){r&&r(c,{changedFields:u,forms:l.current}),a.triggerFormChange(c,u)},triggerFormFinish:function(c,u){o&&o(c,{values:u,forms:l.current}),a.triggerFormFinish(c,u)},registerForm:function(c,u){c&&(l.current=U(U({},l.current),{},V({},c,u))),a.registerForm(c,u)},unregisterForm:function(c){var u=U({},l.current);delete u[c],l.current=u,a.unregisterForm(c)}}),children:i})},c_=["name","initialValues","fields","form","preserve","children","component","validateMessages","validateTrigger","onValuesChange","onFieldsChange","onFinish","onFinishFailed"],u_=function(t,n){var r=t.name,o=t.initialValues,i=t.fields,a=t.form,l=t.preserve,s=t.children,c=t.component,u=c===void 0?"form":c,d=t.validateMessages,v=t.validateTrigger,h=v===void 0?"onChange":v,g=t.onValuesChange,p=t.onFieldsChange,b=t.onFinish,m=t.onFinishFailed,y=Je(t,c_),S=f.exports.useContext(mg),x=Lw(a),$=G(x,1),E=$[0],w=E.getInternalHooks(Si),R=w.useSubscribe,P=w.setInitialValues,N=w.setCallbacks,I=w.setValidateMessages,z=w.setPreserve,F=w.destroyForm;f.exports.useImperativeHandle(n,function(){return E}),f.exports.useEffect(function(){return S.registerForm(r,E),function(){S.unregisterForm(r)}},[S,E,r]),I(U(U({},S.validateMessages),d)),N({onValuesChange:g,onFieldsChange:function(k){if(S.triggerFormChange(r,k),p){for(var j=arguments.length,H=new Array(j>1?j-1:0),W=1;W{let{children:t,status:n,override:r}=e;const o=f.exports.useContext(Jr),i=f.exports.useMemo(()=>{const a=Object.assign({},o);return r&&delete a.isFormItemInput,n&&(delete a.status,delete a.hasFeedback,delete a.feedbackIcon),a},[n,r,o]);return C(Jr.Provider,{value:i,children:t})},v_=f.exports.createContext(void 0),p_=e=>({animationDuration:e,animationFillMode:"both"}),g_=e=>({animationDuration:e,animationFillMode:"both"}),rf=function(e,t,n,r){const i=(arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1)?"&":"";return{[` + ${i}${e}-enter, + ${i}${e}-appear + `]:Object.assign(Object.assign({},p_(r)),{animationPlayState:"paused"}),[`${i}${e}-leave`]:Object.assign(Object.assign({},g_(r)),{animationPlayState:"paused"}),[` + ${i}${e}-enter${e}-enter-active, + ${i}${e}-appear${e}-appear-active + `]:{animationName:t,animationPlayState:"running"},[`${i}${e}-leave${e}-leave-active`]:{animationName:n,animationPlayState:"running",pointerEvents:"none"}}},h_=new Ct("antFadeIn",{"0%":{opacity:0},"100%":{opacity:1}}),m_=new Ct("antFadeOut",{"0%":{opacity:1},"100%":{opacity:0}}),zw=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;const{antCls:n}=e,r=`${n}-fade`,o=t?"&":"";return[rf(r,h_,m_,e.motionDurationMid,t),{[` + ${o}${r}-enter, + ${o}${r}-appear + `]:{opacity:0,animationTimingFunction:"linear"},[`${o}${r}-leave`]:{animationTimingFunction:"linear"}}]},y_=new Ct("antMoveDownIn",{"0%":{transform:"translate3d(0, 100%, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),b_=new Ct("antMoveDownOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(0, 100%, 0)",transformOrigin:"0 0",opacity:0}}),S_=new Ct("antMoveLeftIn",{"0%":{transform:"translate3d(-100%, 0, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),C_=new Ct("antMoveLeftOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(-100%, 0, 0)",transformOrigin:"0 0",opacity:0}}),x_=new Ct("antMoveRightIn",{"0%":{transform:"translate3d(100%, 0, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),w_=new Ct("antMoveRightOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(100%, 0, 0)",transformOrigin:"0 0",opacity:0}}),$_=new Ct("antMoveUpIn",{"0%":{transform:"translate3d(0, -100%, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),E_=new Ct("antMoveUpOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(0, -100%, 0)",transformOrigin:"0 0",opacity:0}}),M_={"move-up":{inKeyframes:$_,outKeyframes:E_},"move-down":{inKeyframes:y_,outKeyframes:b_},"move-left":{inKeyframes:S_,outKeyframes:C_},"move-right":{inKeyframes:x_,outKeyframes:w_}},Zu=(e,t)=>{const{antCls:n}=e,r=`${n}-${t}`,{inKeyframes:o,outKeyframes:i}=M_[t];return[rf(r,o,i,e.motionDurationMid),{[` + ${r}-enter, + ${r}-appear + `]:{opacity:0,animationTimingFunction:e.motionEaseOutCirc},[`${r}-leave`]:{animationTimingFunction:e.motionEaseInOutCirc}}]},nm=new Ct("antSlideUpIn",{"0%":{transform:"scaleY(0.8)",transformOrigin:"0% 0%",opacity:0},"100%":{transform:"scaleY(1)",transformOrigin:"0% 0%",opacity:1}}),rm=new Ct("antSlideUpOut",{"0%":{transform:"scaleY(1)",transformOrigin:"0% 0%",opacity:1},"100%":{transform:"scaleY(0.8)",transformOrigin:"0% 0%",opacity:0}}),om=new Ct("antSlideDownIn",{"0%":{transform:"scaleY(0.8)",transformOrigin:"100% 100%",opacity:0},"100%":{transform:"scaleY(1)",transformOrigin:"100% 100%",opacity:1}}),im=new Ct("antSlideDownOut",{"0%":{transform:"scaleY(1)",transformOrigin:"100% 100%",opacity:1},"100%":{transform:"scaleY(0.8)",transformOrigin:"100% 100%",opacity:0}}),O_=new Ct("antSlideLeftIn",{"0%":{transform:"scaleX(0.8)",transformOrigin:"0% 0%",opacity:0},"100%":{transform:"scaleX(1)",transformOrigin:"0% 0%",opacity:1}}),R_=new Ct("antSlideLeftOut",{"0%":{transform:"scaleX(1)",transformOrigin:"0% 0%",opacity:1},"100%":{transform:"scaleX(0.8)",transformOrigin:"0% 0%",opacity:0}}),I_=new Ct("antSlideRightIn",{"0%":{transform:"scaleX(0.8)",transformOrigin:"100% 0%",opacity:0},"100%":{transform:"scaleX(1)",transformOrigin:"100% 0%",opacity:1}}),P_=new Ct("antSlideRightOut",{"0%":{transform:"scaleX(1)",transformOrigin:"100% 0%",opacity:1},"100%":{transform:"scaleX(0.8)",transformOrigin:"100% 0%",opacity:0}}),T_={"slide-up":{inKeyframes:nm,outKeyframes:rm},"slide-down":{inKeyframes:om,outKeyframes:im},"slide-left":{inKeyframes:O_,outKeyframes:R_},"slide-right":{inKeyframes:I_,outKeyframes:P_}},Xa=(e,t)=>{const{antCls:n}=e,r=`${n}-${t}`,{inKeyframes:o,outKeyframes:i}=T_[t];return[rf(r,o,i,e.motionDurationMid),{[` + ${r}-enter, + ${r}-appear + `]:{transform:"scale(0)",transformOrigin:"0% 0%",opacity:0,animationTimingFunction:e.motionEaseOutQuint,["&-prepare"]:{transform:"scale(1)"}},[`${r}-leave`]:{animationTimingFunction:e.motionEaseInQuint}}]},N_=new Ct("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),__=new Ct("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),fb=new Ct("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),vb=new Ct("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),A_=new Ct("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),D_=new Ct("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),L_=new Ct("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),z_=new Ct("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}}),F_=new Ct("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),k_=new Ct("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}}),B_=new Ct("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),j_=new Ct("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}}),H_={zoom:{inKeyframes:N_,outKeyframes:__},"zoom-big":{inKeyframes:fb,outKeyframes:vb},"zoom-big-fast":{inKeyframes:fb,outKeyframes:vb},"zoom-left":{inKeyframes:L_,outKeyframes:z_},"zoom-right":{inKeyframes:F_,outKeyframes:k_},"zoom-up":{inKeyframes:A_,outKeyframes:D_},"zoom-down":{inKeyframes:B_,outKeyframes:j_}},of=(e,t)=>{const{antCls:n}=e,r=`${n}-${t}`,{inKeyframes:o,outKeyframes:i}=H_[t];return[rf(r,o,i,t==="zoom-big-fast"?e.motionDurationFast:e.motionDurationMid),{[` + ${r}-enter, + ${r}-appear + `]:{transform:"scale(0)",opacity:0,animationTimingFunction:e.motionEaseOutCirc,"&-prepare":{transform:"none"}},[`${r}-leave`]:{animationTimingFunction:e.motionEaseInOutCirc}}]};function pb(e){return{position:e,inset:0}}const Fw=e=>{const{componentCls:t,antCls:n}=e;return[{[`${t}-root`]:{[`${t}${n}-zoom-enter, ${t}${n}-zoom-appear`]:{transform:"none",opacity:0,animationDuration:e.motionDurationSlow,userSelect:"none"},[`${t}${n}-zoom-leave ${t}-content`]:{pointerEvents:"none"},[`${t}-mask`]:Object.assign(Object.assign({},pb("fixed")),{zIndex:e.zIndexPopupBase,height:"100%",backgroundColor:e.colorBgMask,pointerEvents:"none",[`${t}-hidden`]:{display:"none"}}),[`${t}-wrap`]:Object.assign(Object.assign({},pb("fixed")),{zIndex:e.zIndexPopupBase,overflow:"auto",outline:0,WebkitOverflowScrolling:"touch"})}},{[`${t}-root`]:zw(e)}]},W_=e=>{const{componentCls:t}=e;return[{[`${t}-root`]:{[`${t}-wrap-rtl`]:{direction:"rtl"},[`${t}-centered`]:{textAlign:"center","&::before":{display:"inline-block",width:0,height:"100%",verticalAlign:"middle",content:'""'},[t]:{top:0,display:"inline-block",paddingBottom:0,textAlign:"start",verticalAlign:"middle"}},[`@media (max-width: ${e.screenSMMax}px)`]:{[t]:{maxWidth:"calc(100vw - 16px)",margin:`${X(e.marginXS)} auto`},[`${t}-centered`]:{[t]:{flex:1}}}}},{[t]:Object.assign(Object.assign({},Qt(e)),{pointerEvents:"none",position:"relative",top:100,width:"auto",maxWidth:`calc(100vw - ${X(e.calc(e.margin).mul(2).equal())})`,margin:"0 auto",paddingBottom:e.paddingLG,[`${t}-title`]:{margin:0,color:e.titleColor,fontWeight:e.fontWeightStrong,fontSize:e.titleFontSize,lineHeight:e.titleLineHeight,wordWrap:"break-word"},[`${t}-content`]:{position:"relative",backgroundColor:e.contentBg,backgroundClip:"padding-box",border:0,borderRadius:e.borderRadiusLG,boxShadow:e.boxShadow,pointerEvents:"auto",padding:e.contentPadding},[`${t}-close`]:Object.assign({position:"absolute",top:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),insetInlineEnd:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),zIndex:e.calc(e.zIndexPopupBase).add(10).equal(),padding:0,color:e.modalCloseIconColor,fontWeight:e.fontWeightStrong,lineHeight:1,textDecoration:"none",background:"transparent",borderRadius:e.borderRadiusSM,width:e.modalCloseBtnSize,height:e.modalCloseBtnSize,border:0,outline:0,cursor:"pointer",transition:`color ${e.motionDurationMid}, background-color ${e.motionDurationMid}`,"&-x":{display:"flex",fontSize:e.fontSizeLG,fontStyle:"normal",lineHeight:`${X(e.modalCloseBtnSize)}`,justifyContent:"center",textTransform:"none",textRendering:"auto"},"&:hover":{color:e.modalIconHoverColor,backgroundColor:e.closeBtnHoverBg,textDecoration:"none"},"&:active":{backgroundColor:e.closeBtnActiveBg}},Xd(e)),[`${t}-header`]:{color:e.colorText,background:e.headerBg,borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`,marginBottom:e.headerMarginBottom,padding:e.headerPadding,borderBottom:e.headerBorderBottom},[`${t}-body`]:{fontSize:e.fontSize,lineHeight:e.lineHeight,wordWrap:"break-word",padding:e.bodyPadding},[`${t}-footer`]:{textAlign:"end",background:e.footerBg,marginTop:e.footerMarginTop,padding:e.footerPadding,borderTop:e.footerBorderTop,borderRadius:e.footerBorderRadius,[`> ${e.antCls}-btn + ${e.antCls}-btn`]:{marginInlineStart:e.marginXS}},[`${t}-open`]:{overflow:"hidden"}})},{[`${t}-pure-panel`]:{top:"auto",padding:0,display:"flex",flexDirection:"column",[`${t}-content, + ${t}-body, + ${t}-confirm-body-wrapper`]:{display:"flex",flexDirection:"column",flex:"auto"},[`${t}-confirm-body`]:{marginBottom:"auto"}}}]},V_=e=>{const{componentCls:t}=e;return{[`${t}-root`]:{[`${t}-wrap-rtl`]:{direction:"rtl",[`${t}-confirm-body`]:{direction:"rtl"}}}}},U_=e=>{const t=e.padding,n=e.fontSizeHeading5,r=e.lineHeightHeading5;return $t(e,{modalHeaderHeight:e.calc(e.calc(r).mul(n).equal()).add(e.calc(t).mul(2).equal()).equal(),modalFooterBorderColorSplit:e.colorSplit,modalFooterBorderStyle:e.lineType,modalFooterBorderWidth:e.lineWidth,modalIconHoverColor:e.colorIconHover,modalCloseIconColor:e.colorIcon,modalCloseBtnSize:e.fontHeight,modalConfirmIconSize:e.fontHeight,modalTitleHeight:e.calc(e.titleFontSize).mul(e.titleLineHeight).equal()})},Y_=e=>({footerBg:"transparent",headerBg:e.colorBgElevated,titleLineHeight:e.lineHeightHeading5,titleFontSize:e.fontSizeHeading5,contentBg:e.colorBgElevated,titleColor:e.colorTextHeading,closeBtnHoverBg:e.wireframe?"transparent":e.colorFillContent,closeBtnActiveBg:e.wireframe?"transparent":e.colorFillContentHover,contentPadding:e.wireframe?0:`${X(e.paddingMD)} ${X(e.paddingContentHorizontalLG)}`,headerPadding:e.wireframe?`${X(e.padding)} ${X(e.paddingLG)}`:0,headerBorderBottom:e.wireframe?`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`:"none",headerMarginBottom:e.wireframe?0:e.marginXS,bodyPadding:e.wireframe?e.paddingLG:0,footerPadding:e.wireframe?`${X(e.paddingXS)} ${X(e.padding)}`:0,footerBorderTop:e.wireframe?`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`:"none",footerBorderRadius:e.wireframe?`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`:0,footerMarginTop:e.wireframe?0:e.marginSM,confirmBodyPadding:e.wireframe?`${X(e.padding*2)} ${X(e.padding*2)} ${X(e.paddingLG)}`:0,confirmIconMarginInlineEnd:e.wireframe?e.margin:e.marginSM,confirmBtnsMarginTop:e.wireframe?e.marginLG:e.marginSM});vn("Modal",e=>{const t=U_(e);return[W_(t),V_(t),Fw(t),of(t,"zoom")]},Y_,{unitless:{titleLineHeight:!0}});function G_(e){return t=>C(ai,{theme:{token:{motion:!1,zIndexPopupBase:0}},children:C(e,{...Object.assign({},t)})})}const K_=(e,t,n,r)=>G_(i=>{const{prefixCls:a,style:l}=i,s=f.exports.useRef(null),[c,u]=f.exports.useState(0),[d,v]=f.exports.useState(0),[h,g]=kt(!1,{value:i.open}),{getPrefixCls:p}=f.exports.useContext(ot),b=p(t||"select",a);f.exports.useEffect(()=>{if(g(!0),typeof ResizeObserver<"u"){const S=new ResizeObserver($=>{const E=$[0].target;u(E.offsetHeight+8),v(E.offsetWidth)}),x=setInterval(()=>{var $;const E=n?`.${n(b)}`:`.${b}-dropdown`,w=($=s.current)===null||$===void 0?void 0:$.querySelector(E);w&&(clearInterval(x),S.observe(w))},10);return()=>{clearInterval(x),S.disconnect()}}},[]);let m=Object.assign(Object.assign({},i),{style:Object.assign(Object.assign({},l),{margin:0}),open:h,visible:h,getPopupContainer:()=>s.current});return r&&(m=r(m)),C("div",{ref:s,style:{paddingBottom:c,position:"relative",minWidth:d},children:C(e,{...Object.assign({},m)})})}),q_=K_,am=function(){if(typeof navigator>"u"||typeof window>"u")return!1;var e=navigator.userAgent||navigator.vendor||window.opera;return/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(e)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(e==null?void 0:e.substr(0,4))};var af=function(t){var n=t.className,r=t.customizeIcon,o=t.customizeIconProps,i=t.children,a=t.onMouseDown,l=t.onClick,s=typeof r=="function"?r(o):r;return C("span",{className:n,onMouseDown:function(u){u.preventDefault(),a==null||a(u)},style:{userSelect:"none",WebkitUserSelect:"none"},unselectable:"on",onClick:l,"aria-hidden":!0,children:s!==void 0?s:C("span",{className:te(n.split(/\s+/).map(function(c){return"".concat(c,"-icon")})),children:i})})},X_=function(t,n,r,o,i){var a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:!1,l=arguments.length>6?arguments[6]:void 0,s=arguments.length>7?arguments[7]:void 0,c=lt.useMemo(function(){if(Qe(o)==="object")return o.clearIcon;if(i)return i},[o,i]),u=lt.useMemo(function(){return!!(!a&&!!o&&(r.length||l)&&!(s==="combobox"&&l===""))},[o,a,r.length,l,s]);return{allowClear:u,clearIcon:C(af,{className:"".concat(t,"-clear"),onMouseDown:n,customizeIcon:c,children:"\xD7"})}},kw=f.exports.createContext(null);function Q_(){return f.exports.useContext(kw)}function Z_(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:10,t=f.exports.useState(!1),n=G(t,2),r=n[0],o=n[1],i=f.exports.useRef(null),a=function(){window.clearTimeout(i.current)};f.exports.useEffect(function(){return a},[]);var l=function(c,u){a(),i.current=window.setTimeout(function(){o(c),u&&u()},e)};return[r,l,a]}function Bw(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:250,t=f.exports.useRef(null),n=f.exports.useRef(null);f.exports.useEffect(function(){return function(){window.clearTimeout(n.current)}},[]);function r(o){(o||t.current===null)&&(t.current=o),window.clearTimeout(n.current),n.current=window.setTimeout(function(){t.current=null},e)}return[function(){return t.current},r]}function J_(e,t,n,r){var o=f.exports.useRef(null);o.current={open:t,triggerOpen:n,customizedTrigger:r},f.exports.useEffect(function(){function i(a){var l;if(!((l=o.current)!==null&&l!==void 0&&l.customizedTrigger)){var s=a.target;s.shadowRoot&&a.composed&&(s=a.composedPath()[0]||s),o.current.open&&e().filter(function(c){return c}).every(function(c){return!c.contains(s)&&c!==s})&&o.current.triggerOpen(!1)}}return window.addEventListener("mousedown",i),function(){return window.removeEventListener("mousedown",i)}},[])}var eA=["prefixCls","invalidate","item","renderItem","responsive","responsiveDisabled","registerSize","itemKey","className","style","children","display","order","component"],qi=void 0;function tA(e,t){var n=e.prefixCls,r=e.invalidate,o=e.item,i=e.renderItem,a=e.responsive,l=e.responsiveDisabled,s=e.registerSize,c=e.itemKey,u=e.className,d=e.style,v=e.children,h=e.display,g=e.order,p=e.component,b=p===void 0?"div":p,m=Je(e,eA),y=a&&!h;function S(R){s(c,R)}f.exports.useEffect(function(){return function(){S(null)}},[]);var x=i&&o!==qi?i(o):v,$;r||($={opacity:y?0:1,height:y?0:qi,overflowY:y?"hidden":qi,order:a?g:qi,pointerEvents:y?"none":qi,position:y?"absolute":qi});var E={};y&&(E["aria-hidden"]=!0);var w=C(b,{className:te(!r&&n,u),style:U(U({},$),d),...E,...m,ref:t,children:x});return a&&(w=C(mr,{onResize:function(P){var N=P.offsetWidth;S(N)},disabled:l,children:w})),w}var Jl=f.exports.forwardRef(tA);Jl.displayName="Item";function nA(e){if(typeof MessageChannel>"u")St(e);else{var t=new MessageChannel;t.port1.onmessage=function(){return e()},t.port2.postMessage(void 0)}}function rA(){var e=f.exports.useRef(null),t=function(r){e.current||(e.current=[],nA(function(){Gn.exports.unstable_batchedUpdates(function(){e.current.forEach(function(o){o()}),e.current=null})})),e.current.push(r)};return t}function Cl(e,t){var n=f.exports.useState(t),r=G(n,2),o=r[0],i=r[1],a=hn(function(l){e(function(){i(l)})});return[o,a]}var Ju=lt.createContext(null),oA=["component"],iA=["className"],aA=["className"],lA=function(t,n){var r=f.exports.useContext(Ju);if(!r){var o=t.component,i=o===void 0?"div":o,a=Je(t,oA);return C(i,{...a,ref:n})}var l=r.className,s=Je(r,iA),c=t.className,u=Je(t,aA);return C(Ju.Provider,{value:null,children:C(Jl,{ref:n,className:te(l,c),...s,...u})})},jw=f.exports.forwardRef(lA);jw.displayName="RawItem";var sA=["prefixCls","data","renderItem","renderRawItem","itemKey","itemWidth","ssr","style","className","maxCount","renderRest","renderRawRest","suffix","component","itemComponent","onVisibleChange"],Hw="responsive",Ww="invalidate";function cA(e){return"+ ".concat(e.length," ...")}function uA(e,t){var n=e.prefixCls,r=n===void 0?"rc-overflow":n,o=e.data,i=o===void 0?[]:o,a=e.renderItem,l=e.renderRawItem,s=e.itemKey,c=e.itemWidth,u=c===void 0?10:c,d=e.ssr,v=e.style,h=e.className,g=e.maxCount,p=e.renderRest,b=e.renderRawRest,m=e.suffix,y=e.component,S=y===void 0?"div":y,x=e.itemComponent,$=e.onVisibleChange,E=Je(e,sA),w=d==="full",R=rA(),P=Cl(R,null),N=G(P,2),I=N[0],z=N[1],F=I||0,T=Cl(R,new Map),D=G(T,2),_=D[0],O=D[1],M=Cl(R,0),L=G(M,2),A=L[0],B=L[1],k=Cl(R,0),j=G(k,2),H=j[0],W=j[1],Y=Cl(R,0),K=G(Y,2),q=K[0],ee=K[1],Z=f.exports.useState(null),Q=G(Z,2),ne=Q[0],ae=Q[1],J=f.exports.useState(null),re=G(J,2),fe=re[0],ve=re[1],pe=f.exports.useMemo(function(){return fe===null&&w?Number.MAX_SAFE_INTEGER:fe||0},[fe,I]),oe=f.exports.useState(!1),se=G(oe,2),le=se[0],Ce=se[1],ce="".concat(r,"-item"),de=Math.max(A,H),xe=g===Hw,he=i.length&&xe,ke=g===Ww,we=he||typeof g=="number"&&i.length>g,ge=f.exports.useMemo(function(){var be=i;return he?I===null&&w?be=i:be=i.slice(0,Math.min(i.length,F/u)):typeof g=="number"&&(be=i.slice(0,g)),be},[i,u,I,g,he]),Pe=f.exports.useMemo(function(){return he?i.slice(pe+1):i.slice(ge.length)},[i,ge,he,pe]),Se=f.exports.useCallback(function(be,Ae){var Me;return typeof s=="function"?s(be):(Me=s&&(be==null?void 0:be[s]))!==null&&Me!==void 0?Me:Ae},[s]),st=f.exports.useCallback(a||function(be){return be},[a]);function nt(be,Ae,Me){fe===be&&(Ae===void 0||Ae===ne)||(ve(be),Me||(Ce(beF){nt($e-1,be-Te-q+H);break}}m&&qe(0)+q>F&&ae(null)}},[F,_,H,q,Se,ge]);var it=le&&!!Pe.length,ft={};ne!==null&&he&&(ft={position:"absolute",left:ne,top:0});var ut={prefixCls:ce,responsive:he,component:x,invalidate:ke},Ue=l?function(be,Ae){var Me=Se(be,Ae);return C(Ju.Provider,{value:U(U({},ut),{},{order:Ae,item:be,itemKey:Me,registerSize:Ee,display:Ae<=pe}),children:l(be,Ae)},Me)}:function(be,Ae){var Me=Se(be,Ae);return f.exports.createElement(Jl,{...ut,order:Ae,key:Me,item:be,renderItem:st,itemKey:Me,registerSize:Ee,display:Ae<=pe})},He,Xe={order:it?pe:Number.MAX_SAFE_INTEGER,className:"".concat(ce,"-rest"),registerSize:_e,display:it};if(b)b&&(He=C(Ju.Provider,{value:U(U({},ut),Xe),children:b(Pe)}));else{var Le=p||cA;He=C(Jl,{...ut,...Xe,children:typeof Le=="function"?Le(Pe):Le})}var Re=ie(S,{className:te(!ke&&r,h),style:v,ref:t,...E,children:[ge.map(Ue),we?He:null,m&&C(Jl,{...ut,responsive:xe,responsiveDisabled:!he,order:pe,className:"".concat(ce,"-suffix"),registerSize:Be,display:!0,style:ft,children:m})]});return xe&&(Re=C(mr,{onResize:Ne,disabled:!he,children:Re})),Re}var Zr=f.exports.forwardRef(uA);Zr.displayName="Overflow";Zr.Item=jw;Zr.RESPONSIVE=Hw;Zr.INVALIDATE=Ww;var dA=function(t,n){var r,o=t.prefixCls,i=t.id,a=t.inputElement,l=t.disabled,s=t.tabIndex,c=t.autoFocus,u=t.autoComplete,d=t.editable,v=t.activeDescendantId,h=t.value,g=t.maxLength,p=t.onKeyDown,b=t.onMouseDown,m=t.onChange,y=t.onPaste,S=t.onCompositionStart,x=t.onCompositionEnd,$=t.open,E=t.attrs,w=a||C("input",{}),R=w,P=R.ref,N=R.props,I=N.onKeyDown,z=N.onChange,F=N.onMouseDown,T=N.onCompositionStart,D=N.onCompositionEnd,_=N.style;return"maxLength"in w.props,w=f.exports.cloneElement(w,U(U(U({type:"search"},N),{},{id:i,ref:xr(n,P),disabled:l,tabIndex:s,autoComplete:u||"off",autoFocus:c,className:te("".concat(o,"-selection-search-input"),(r=w)===null||r===void 0||(r=r.props)===null||r===void 0?void 0:r.className),role:"combobox","aria-expanded":$||!1,"aria-haspopup":"listbox","aria-owns":"".concat(i,"_list"),"aria-autocomplete":"list","aria-controls":"".concat(i,"_list"),"aria-activedescendant":$?v:void 0},E),{},{value:d?h:"",maxLength:g,readOnly:!d,unselectable:d?null:"on",style:U(U({},_),{},{opacity:d?null:0}),onKeyDown:function(M){p(M),I&&I(M)},onMouseDown:function(M){b(M),F&&F(M)},onChange:function(M){m(M),z&&z(M)},onCompositionStart:function(M){S(M),T&&T(M)},onCompositionEnd:function(M){x(M),D&&D(M)},onPaste:y})),w},Vw=f.exports.forwardRef(dA);function Uw(e){return Array.isArray(e)?e:e!==void 0?[e]:[]}var fA=typeof window<"u"&&window.document&&window.document.documentElement,vA=fA;function pA(e){return e!=null}function gA(e){return!e&&e!==0}function gb(e){return["string","number"].includes(Qe(e))}function Yw(e){var t=void 0;return e&&(gb(e.title)?t=e.title.toString():gb(e.label)&&(t=e.label.toString())),t}function hA(e,t){vA?f.exports.useLayoutEffect(e,t):f.exports.useEffect(e,t)}function mA(e){var t;return(t=e.key)!==null&&t!==void 0?t:e.value}var hb=function(t){t.preventDefault(),t.stopPropagation()},yA=function(t){var n=t.id,r=t.prefixCls,o=t.values,i=t.open,a=t.searchValue,l=t.autoClearSearchValue,s=t.inputRef,c=t.placeholder,u=t.disabled,d=t.mode,v=t.showSearch,h=t.autoFocus,g=t.autoComplete,p=t.activeDescendantId,b=t.tabIndex,m=t.removeIcon,y=t.maxTagCount,S=t.maxTagTextLength,x=t.maxTagPlaceholder,$=x===void 0?function(ae){return"+ ".concat(ae.length," ...")}:x,E=t.tagRender,w=t.onToggleOpen,R=t.onRemove,P=t.onInputChange,N=t.onInputPaste,I=t.onInputKeyDown,z=t.onInputMouseDown,F=t.onInputCompositionStart,T=t.onInputCompositionEnd,D=f.exports.useRef(null),_=f.exports.useState(0),O=G(_,2),M=O[0],L=O[1],A=f.exports.useState(!1),B=G(A,2),k=B[0],j=B[1],H="".concat(r,"-selection"),W=i||d==="multiple"&&l===!1||d==="tags"?a:"",Y=d==="tags"||d==="multiple"&&l===!1||v&&(i||k);hA(function(){L(D.current.scrollWidth)},[W]);var K=function(J,re,fe,ve,pe){return ie("span",{title:Yw(J),className:te("".concat(H,"-item"),V({},"".concat(H,"-item-disabled"),fe)),children:[C("span",{className:"".concat(H,"-item-content"),children:re}),ve&&C(af,{className:"".concat(H,"-item-remove"),onMouseDown:hb,onClick:pe,customizeIcon:m,children:"\xD7"})]})},q=function(J,re,fe,ve,pe){var oe=function(le){hb(le),w(!i)};return C("span",{onMouseDown:oe,children:E({label:re,value:J,disabled:fe,closable:ve,onClose:pe})})},ee=function(J){var re=J.disabled,fe=J.label,ve=J.value,pe=!u&&!re,oe=fe;if(typeof S=="number"&&(typeof fe=="string"||typeof fe=="number")){var se=String(oe);se.length>S&&(oe="".concat(se.slice(0,S),"..."))}var le=function(ce){ce&&ce.stopPropagation(),R(J)};return typeof E=="function"?q(ve,oe,re,pe,le):K(J,oe,re,pe,le)},Z=function(J){var re=typeof $=="function"?$(J):$;return K({title:re},re,!1)},Q=ie("div",{className:"".concat(H,"-search"),style:{width:M},onFocus:function(){j(!0)},onBlur:function(){j(!1)},children:[C(Vw,{ref:s,open:i,prefixCls:r,id:n,inputElement:null,disabled:u,autoFocus:h,autoComplete:g,editable:Y,activeDescendantId:p,value:W,onKeyDown:I,onMouseDown:z,onChange:P,onPaste:N,onCompositionStart:F,onCompositionEnd:T,tabIndex:b,attrs:Ka(t,!0)}),ie("span",{ref:D,className:"".concat(H,"-search-mirror"),"aria-hidden":!0,children:[W,"\xA0"]})]}),ne=C(Zr,{prefixCls:"".concat(H,"-overflow"),data:o,renderItem:ee,renderRest:Z,suffix:Q,itemKey:mA,maxCount:y});return ie(Tt,{children:[ne,!o.length&&!W&&C("span",{className:"".concat(H,"-placeholder"),children:c})]})},bA=function(t){var n=t.inputElement,r=t.prefixCls,o=t.id,i=t.inputRef,a=t.disabled,l=t.autoFocus,s=t.autoComplete,c=t.activeDescendantId,u=t.mode,d=t.open,v=t.values,h=t.placeholder,g=t.tabIndex,p=t.showSearch,b=t.searchValue,m=t.activeValue,y=t.maxLength,S=t.onInputKeyDown,x=t.onInputMouseDown,$=t.onInputChange,E=t.onInputPaste,w=t.onInputCompositionStart,R=t.onInputCompositionEnd,P=t.title,N=f.exports.useState(!1),I=G(N,2),z=I[0],F=I[1],T=u==="combobox",D=T||p,_=v[0],O=b||"";T&&m&&!z&&(O=m),f.exports.useEffect(function(){T&&F(!1)},[T,m]);var M=u!=="combobox"&&!d&&!p?!1:!!O,L=P===void 0?Yw(_):P,A=f.exports.useMemo(function(){return _?null:C("span",{className:"".concat(r,"-selection-placeholder"),style:M?{visibility:"hidden"}:void 0,children:h})},[_,M,h,r]);return ie(Tt,{children:[C("span",{className:"".concat(r,"-selection-search"),children:C(Vw,{ref:i,prefixCls:r,id:o,open:d,inputElement:n,disabled:a,autoFocus:l,autoComplete:s,editable:D,activeDescendantId:c,value:O,onKeyDown:S,onMouseDown:x,onChange:function(k){F(!0),$(k)},onPaste:E,onCompositionStart:w,onCompositionEnd:R,tabIndex:g,attrs:Ka(t,!0),maxLength:T?y:void 0})}),!T&&_?C("span",{className:"".concat(r,"-selection-item"),title:L,style:M?{visibility:"hidden"}:void 0,children:_.label}):null,A]})};function SA(e){return![ue.ESC,ue.SHIFT,ue.BACKSPACE,ue.TAB,ue.WIN_KEY,ue.ALT,ue.META,ue.WIN_KEY_RIGHT,ue.CTRL,ue.SEMICOLON,ue.EQUALS,ue.CAPS_LOCK,ue.CONTEXT_MENU,ue.F1,ue.F2,ue.F3,ue.F4,ue.F5,ue.F6,ue.F7,ue.F8,ue.F9,ue.F10,ue.F11,ue.F12].includes(e)}var CA=function(t,n){var r=f.exports.useRef(null),o=f.exports.useRef(!1),i=t.prefixCls,a=t.open,l=t.mode,s=t.showSearch,c=t.tokenWithEnter,u=t.autoClearSearchValue,d=t.onSearch,v=t.onSearchSubmit,h=t.onToggleOpen,g=t.onInputKeyDown,p=t.domRef;f.exports.useImperativeHandle(n,function(){return{focus:function(){r.current.focus()},blur:function(){r.current.blur()}}});var b=Bw(0),m=G(b,2),y=m[0],S=m[1],x=function(O){var M=O.which;(M===ue.UP||M===ue.DOWN)&&O.preventDefault(),g&&g(O),M===ue.ENTER&&l==="tags"&&!o.current&&!a&&(v==null||v(O.target.value)),SA(M)&&h(!0)},$=function(){S(!0)},E=f.exports.useRef(null),w=function(O){d(O,!0,o.current)!==!1&&h(!0)},R=function(){o.current=!0},P=function(O){o.current=!1,l!=="combobox"&&w(O.target.value)},N=function(O){var M=O.target.value;if(c&&E.current&&/[\r\n]/.test(E.current)){var L=E.current.replace(/[\r\n]+$/,"").replace(/\r\n/g," ").replace(/[\r\n]/g," ");M=M.replace(L,E.current)}E.current=null,w(M)},I=function(O){var M=O.clipboardData,L=M==null?void 0:M.getData("text");E.current=L||""},z=function(O){var M=O.target;if(M!==r.current){var L=document.body.style.msTouchAction!==void 0;L?setTimeout(function(){r.current.focus()}):r.current.focus()}},F=function(O){var M=y();O.target!==r.current&&!M&&l!=="combobox"&&O.preventDefault(),(l!=="combobox"&&(!s||!M)||!a)&&(a&&u!==!1&&d("",!0,!1),h())},T={inputRef:r,onInputKeyDown:x,onInputMouseDown:$,onInputChange:N,onInputPaste:I,onInputCompositionStart:R,onInputCompositionEnd:P},D=l==="multiple"||l==="tags"?C(yA,{...t,...T}):C(bA,{...t,...T});return C("div",{ref:p,className:"".concat(i,"-selector"),onClick:z,onMouseDown:F,children:D})},xA=f.exports.forwardRef(CA);function wA(e){var t=e.prefixCls,n=e.align,r=e.arrow,o=e.arrowPos,i=r||{},a=i.className,l=i.content,s=o.x,c=s===void 0?0:s,u=o.y,d=u===void 0?0:u,v=f.exports.useRef();if(!n||!n.points)return null;var h={position:"absolute"};if(n.autoArrow!==!1){var g=n.points[0],p=n.points[1],b=g[0],m=g[1],y=p[0],S=p[1];b===y||!["t","b"].includes(b)?h.top=d:b==="t"?h.top=0:h.bottom=0,m===S||!["l","r"].includes(m)?h.left=c:m==="l"?h.left=0:h.right=0}return C("div",{ref:v,className:te("".concat(t,"-arrow"),a),style:h,children:l})}function $A(e){var t=e.prefixCls,n=e.open,r=e.zIndex,o=e.mask,i=e.motion;return o?C(to,{...i,motionAppear:!0,visible:n,removeOnLeave:!0,children:function(a){var l=a.className;return C("div",{style:{zIndex:r},className:te("".concat(t,"-mask"),l)})}}):null}var EA=f.exports.memo(function(e){var t=e.children;return t},function(e,t){return t.cache}),MA=f.exports.forwardRef(function(e,t){var n=e.popup,r=e.className,o=e.prefixCls,i=e.style,a=e.target,l=e.onVisibleChanged,s=e.open,c=e.keepDom,u=e.fresh,d=e.onClick,v=e.mask,h=e.arrow,g=e.arrowPos,p=e.align,b=e.motion,m=e.maskMotion,y=e.forceRender,S=e.getPopupContainer,x=e.autoDestroy,$=e.portal,E=e.zIndex,w=e.onMouseEnter,R=e.onMouseLeave,P=e.onPointerEnter,N=e.ready,I=e.offsetX,z=e.offsetY,F=e.offsetR,T=e.offsetB,D=e.onAlign,_=e.onPrepare,O=e.stretch,M=e.targetWidth,L=e.targetHeight,A=typeof n=="function"?n():n,B=s||c,k=(S==null?void 0:S.length)>0,j=f.exports.useState(!S||!k),H=G(j,2),W=H[0],Y=H[1];if(Nt(function(){!W&&k&&a&&Y(!0)},[W,k,a]),!W)return null;var K="auto",q={left:"-1000vw",top:"-1000vh",right:K,bottom:K};if(N||!s){var ee,Z=p.points,Q=p.dynamicInset||((ee=p._experimental)===null||ee===void 0?void 0:ee.dynamicInset),ne=Q&&Z[0][1]==="r",ae=Q&&Z[0][0]==="b";ne?(q.right=F,q.left=K):(q.left=I,q.right=K),ae?(q.bottom=T,q.top=K):(q.top=z,q.bottom=K)}var J={};return O&&(O.includes("height")&&L?J.height=L:O.includes("minHeight")&&L&&(J.minHeight=L),O.includes("width")&&M?J.width=M:O.includes("minWidth")&&M&&(J.minWidth=M)),s||(J.pointerEvents="none"),ie($,{open:y||B,getContainer:S&&function(){return S(a)},autoDestroy:x,children:[C($A,{prefixCls:o,open:s,zIndex:E,mask:v,motion:m}),C(mr,{onResize:D,disabled:!s,children:function(re){return C(to,{motionAppear:!0,motionEnter:!0,motionLeave:!0,removeOnLeave:!1,forceRender:y,leavedClassName:"".concat(o,"-hidden"),...b,onAppearPrepare:_,onEnterPrepare:_,visible:s,onVisibleChanged:function(ve){var pe;b==null||(pe=b.onVisibleChanged)===null||pe===void 0||pe.call(b,ve),l(ve)},children:function(fe,ve){var pe=fe.className,oe=fe.style,se=te(o,pe,r);return ie("div",{ref:xr(re,t,ve),className:se,style:U(U(U(U({"--arrow-x":"".concat(g.x||0,"px"),"--arrow-y":"".concat(g.y||0,"px")},q),J),oe),{},{boxSizing:"border-box",zIndex:E},i),onMouseEnter:w,onMouseLeave:R,onPointerEnter:P,onClick:d,children:[h&&C(wA,{prefixCls:o,arrow:h,arrowPos:g,align:p}),C(EA,{cache:!s&&!u,children:A})]})}})}})]})}),OA=f.exports.forwardRef(function(e,t){var n=e.children,r=e.getTriggerDOMNode,o=ki(n),i=f.exports.useCallback(function(l){zh(t,r?r(l):l)},[r]),a=Fi(i,n.ref);return o?f.exports.cloneElement(n,{ref:a}):n}),mb=f.exports.createContext(null);function yb(e){return e?Array.isArray(e)?e:[e]:[]}function RA(e,t,n,r){return f.exports.useMemo(function(){var o=yb(n!=null?n:t),i=yb(r!=null?r:t),a=new Set(o),l=new Set(i);return e&&(a.has("hover")&&(a.delete("hover"),a.add("click")),l.has("hover")&&(l.delete("hover"),l.add("click"))),[a,l]},[e,t,n,r])}function IA(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[],n=arguments.length>2?arguments[2]:void 0;return n?e[0]===t[0]:e[0]===t[0]&&e[1]===t[1]}function PA(e,t,n,r){for(var o=n.points,i=Object.keys(e),a=0;a1&&arguments[1]!==void 0?arguments[1]:1;return Number.isNaN(e)?t:e}function xl(e){return Rs(parseFloat(e),0)}function Sb(e,t){var n=U({},e);return(t||[]).forEach(function(r){if(!(r instanceof HTMLBodyElement||r instanceof HTMLHtmlElement)){var o=qs(r).getComputedStyle(r),i=o.overflow,a=o.overflowClipMargin,l=o.borderTopWidth,s=o.borderBottomWidth,c=o.borderLeftWidth,u=o.borderRightWidth,d=r.getBoundingClientRect(),v=r.offsetHeight,h=r.clientHeight,g=r.offsetWidth,p=r.clientWidth,b=xl(l),m=xl(s),y=xl(c),S=xl(u),x=Rs(Math.round(d.width/g*1e3)/1e3),$=Rs(Math.round(d.height/v*1e3)/1e3),E=(g-p-y-S)*x,w=(v-h-b-m)*$,R=b*$,P=m*$,N=y*x,I=S*x,z=0,F=0;if(i==="clip"){var T=xl(a);z=T*x,F=T*$}var D=d.x+N-z,_=d.y+R-F,O=D+d.width+2*z-N-I-E,M=_+d.height+2*F-R-P-w;n.left=Math.max(n.left,D),n.top=Math.max(n.top,_),n.right=Math.min(n.right,O),n.bottom=Math.min(n.bottom,M)}}),n}function Cb(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,n="".concat(t),r=n.match(/^(.*)\%$/);return r?e*(parseFloat(r[1])/100):parseFloat(n)}function xb(e,t){var n=t||[],r=G(n,2),o=r[0],i=r[1];return[Cb(e.width,o),Cb(e.height,i)]}function wb(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"";return[e[0],e[1]]}function Xi(e,t){var n=t[0],r=t[1],o,i;return n==="t"?i=e.y:n==="b"?i=e.y+e.height:i=e.y+e.height/2,r==="l"?o=e.x:r==="r"?o=e.x+e.width:o=e.x+e.width/2,{x:o,y:i}}function Mo(e,t){var n={t:"b",b:"t",l:"r",r:"l"};return e.map(function(r,o){return o===t?n[r]||"c":r}).join("")}function TA(e,t,n,r,o,i,a){var l=f.exports.useState({ready:!1,offsetX:0,offsetY:0,offsetR:0,offsetB:0,arrowX:0,arrowY:0,scaleX:1,scaleY:1,align:o[r]||{}}),s=G(l,2),c=s[0],u=s[1],d=f.exports.useRef(0),v=f.exports.useMemo(function(){return t?yg(t):[]},[t]),h=f.exports.useRef({}),g=function(){h.current={}};e||g();var p=hn(function(){if(t&&n&&e){let un=function(tc,ro){var si=arguments.length>2&&arguments[2]!==void 0?arguments[2]:se,Vi=A.x+tc,ul=A.y+ro,yf=Vi+ee,bf=ul+q,Sf=Math.max(Vi,si.left),Cf=Math.max(ul,si.top),je=Math.min(yf,si.right),tt=Math.min(bf,si.bottom);return Math.max(0,(je-Sf)*(tt-Cf))},cl=function(){ct=A.y+Le,We=ct+q,Ve=A.x+Xe,vt=Ve+ee};var Wi=un,iE=cl,y,S,x=t,$=x.ownerDocument,E=qs(x),w=E.getComputedStyle(x),R=w.width,P=w.height,N=w.position,I=x.style.left,z=x.style.top,F=x.style.right,T=x.style.bottom,D=x.style.overflow,_=U(U({},o[r]),i),O=$.createElement("div");(y=x.parentElement)===null||y===void 0||y.appendChild(O),O.style.left="".concat(x.offsetLeft,"px"),O.style.top="".concat(x.offsetTop,"px"),O.style.position=N,O.style.height="".concat(x.offsetHeight,"px"),O.style.width="".concat(x.offsetWidth,"px"),x.style.left="0",x.style.top="0",x.style.right="auto",x.style.bottom="auto",x.style.overflow="hidden";var M;if(Array.isArray(n))M={x:n[0],y:n[1],width:0,height:0};else{var L=n.getBoundingClientRect();M={x:L.x,y:L.y,width:L.width,height:L.height}}var A=x.getBoundingClientRect(),B=$.documentElement,k=B.clientWidth,j=B.clientHeight,H=B.scrollWidth,W=B.scrollHeight,Y=B.scrollTop,K=B.scrollLeft,q=A.height,ee=A.width,Z=M.height,Q=M.width,ne={left:0,top:0,right:k,bottom:j},ae={left:-K,top:-Y,right:H-K,bottom:W-Y},J=_.htmlRegion,re="visible",fe="visibleFirst";J!=="scroll"&&J!==fe&&(J=re);var ve=J===fe,pe=Sb(ae,v),oe=Sb(ne,v),se=J===re?oe:pe,le=ve?oe:se;x.style.left="auto",x.style.top="auto",x.style.right="0",x.style.bottom="0";var Ce=x.getBoundingClientRect();x.style.left=I,x.style.top=z,x.style.right=F,x.style.bottom=T,x.style.overflow=D,(S=x.parentElement)===null||S===void 0||S.removeChild(O);var ce=Rs(Math.round(ee/parseFloat(R)*1e3)/1e3),de=Rs(Math.round(q/parseFloat(P)*1e3)/1e3);if(ce===0||de===0||Wu(n)&&!Jd(n))return;var xe=_.offset,he=_.targetOffset,ke=xb(A,xe),we=G(ke,2),ge=we[0],Pe=we[1],Se=xb(M,he),st=G(Se,2),nt=st[0],Ne=st[1];M.x-=nt,M.y-=Ne;var Ee=_.points||[],_e=G(Ee,2),Be=_e[0],qe=_e[1],it=wb(qe),ft=wb(Be),ut=Xi(M,it),Ue=Xi(A,ft),He=U({},_),Xe=ut.x-Ue.x+ge,Le=ut.y-Ue.y+Pe,Re=un(Xe,Le),be=un(Xe,Le,oe),Ae=Xi(M,["t","l"]),Me=Xi(A,["t","l"]),$e=Xi(M,["b","r"]),Te=Xi(A,["b","r"]),ye=_.overflow||{},Ge=ye.adjustX,Ze=ye.adjustY,et=ye.shiftX,ht=ye.shiftY,mt=function(ro){return typeof ro=="boolean"?ro:ro>=0},ct,We,Ve,vt;cl();var Ie=mt(Ze),ze=ft[0]===it[0];if(Ie&&ft[0]==="t"&&(We>le.bottom||h.current.bt)){var Ke=Le;ze?Ke-=q-Z:Ke=Ae.y-Te.y-Pe;var at=un(Xe,Ke),Gt=un(Xe,Ke,oe);at>Re||at===Re&&(!ve||Gt>=be)?(h.current.bt=!0,Le=Ke,Pe=-Pe,He.points=[Mo(ft,0),Mo(it,0)]):h.current.bt=!1}if(Ie&&ft[0]==="b"&&(ctRe||Zt===Re&&(!ve||Jt>=be)?(h.current.tb=!0,Le=At,Pe=-Pe,He.points=[Mo(ft,0),Mo(it,0)]):h.current.tb=!1}var kn=mt(Ge),qn=ft[1]===it[1];if(kn&&ft[1]==="l"&&(vt>le.right||h.current.rl)){var pn=Xe;qn?pn-=ee-Q:pn=Ae.x-Te.x-ge;var Co=un(pn,Le),xo=un(pn,Le,oe);Co>Re||Co===Re&&(!ve||xo>=be)?(h.current.rl=!0,Xe=pn,ge=-ge,He.points=[Mo(ft,1),Mo(it,1)]):h.current.rl=!1}if(kn&&ft[1]==="r"&&(VeRe||wo===Re&&(!ve||wr>=be)?(h.current.lr=!0,Xe=In,ge=-ge,He.points=[Mo(ft,1),Mo(it,1)]):h.current.lr=!1}cl();var Bn=et===!0?0:et;typeof Bn=="number"&&(Veoe.right&&(Xe-=vt-oe.right-ge,M.x>oe.right-Bn&&(Xe+=M.x-oe.right+Bn)));var sr=ht===!0?0:ht;typeof sr=="number"&&(ctoe.bottom&&(Le-=We-oe.bottom-Pe,M.y>oe.bottom-sr&&(Le+=M.y-oe.bottom+sr)));var $r=A.x+Xe,Ur=$r+ee,Xn=A.y+Le,$o=Xn+q,Er=M.x,bt=Er+Q,dt=M.y,Fe=dt+Z,Ye=Math.max($r,Er),yt=Math.min(Ur,bt),Bt=(Ye+yt)/2,It=Bt-$r,Kt=Math.max(Xn,dt),sn=Math.min($o,Fe),Pn=(Kt+sn)/2,cn=Pn-Xn;a==null||a(t,He);var Tn=Ce.right-A.x-(Xe+A.width),jn=Ce.bottom-A.y-(Le+A.height);u({ready:!0,offsetX:Xe/ce,offsetY:Le/de,offsetR:Tn/ce,offsetB:jn/de,arrowX:It/ce,arrowY:cn/de,scaleX:ce,scaleY:de,align:He})}}),b=function(){d.current+=1;var S=d.current;Promise.resolve().then(function(){d.current===S&&p()})},m=function(){u(function(S){return U(U({},S),{},{ready:!1})})};return Nt(m,[r]),Nt(function(){e||m()},[e]),[c.ready,c.offsetX,c.offsetY,c.offsetR,c.offsetB,c.arrowX,c.arrowY,c.scaleX,c.scaleY,c.align,b]}function NA(e,t,n,r,o){Nt(function(){if(e&&t&&n){let v=function(){r(),o()};var d=v,i=t,a=n,l=yg(i),s=yg(a),c=qs(a),u=new Set([c].concat(Oe(l),Oe(s)));return u.forEach(function(h){h.addEventListener("scroll",v,{passive:!0})}),c.addEventListener("resize",v,{passive:!0}),r(),function(){u.forEach(function(h){h.removeEventListener("scroll",v),c.removeEventListener("resize",v)})}}},[e,t,n])}function _A(e,t,n,r,o,i,a,l){var s=f.exports.useRef(e),c=f.exports.useRef(!1);s.current!==e&&(c.current=!0,s.current=e),f.exports.useEffect(function(){var u=St(function(){c.current=!1});return function(){St.cancel(u)}},[e]),f.exports.useEffect(function(){if(t&&r&&(!o||i)){var u=function(){var E=!1,w=function(N){var I=N.target;E=a(I)},R=function(N){var I=N.target;!c.current&&s.current&&!E&&!a(I)&&l(!1)};return[w,R]},d=u(),v=G(d,2),h=v[0],g=v[1],p=u(),b=G(p,2),m=b[0],y=b[1],S=qs(r);S.addEventListener("mousedown",h,!0),S.addEventListener("click",g,!0),S.addEventListener("contextmenu",g,!0);var x=Hu(n);return x&&(x.addEventListener("mousedown",m,!0),x.addEventListener("click",y,!0),x.addEventListener("contextmenu",y,!0)),function(){S.removeEventListener("mousedown",h,!0),S.removeEventListener("click",g,!0),S.removeEventListener("contextmenu",g,!0),x&&(x.removeEventListener("mousedown",m,!0),x.removeEventListener("click",y,!0),x.removeEventListener("contextmenu",y,!0))}}},[t,n,r,o,i])}var AA=["prefixCls","children","action","showAction","hideAction","popupVisible","defaultPopupVisible","onPopupVisibleChange","afterPopupVisibleChange","mouseEnterDelay","mouseLeaveDelay","focusDelay","blurDelay","mask","maskClosable","getPopupContainer","forceRender","autoDestroy","destroyPopupOnHide","popup","popupClassName","popupStyle","popupPlacement","builtinPlacements","popupAlign","zIndex","stretch","getPopupClassNameFromAlign","fresh","alignPoint","onPopupClick","onPopupAlign","arrow","popupMotion","maskMotion","popupTransitionName","popupAnimation","maskTransitionName","maskAnimation","className","getTriggerDOMNode"];function DA(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:nf,t=f.exports.forwardRef(function(n,r){var o=n.prefixCls,i=o===void 0?"rc-trigger-popup":o,a=n.children,l=n.action,s=l===void 0?"hover":l,c=n.showAction,u=n.hideAction,d=n.popupVisible,v=n.defaultPopupVisible,h=n.onPopupVisibleChange,g=n.afterPopupVisibleChange,p=n.mouseEnterDelay,b=n.mouseLeaveDelay,m=b===void 0?.1:b,y=n.focusDelay,S=n.blurDelay,x=n.mask,$=n.maskClosable,E=$===void 0?!0:$,w=n.getPopupContainer,R=n.forceRender,P=n.autoDestroy,N=n.destroyPopupOnHide,I=n.popup,z=n.popupClassName,F=n.popupStyle,T=n.popupPlacement,D=n.builtinPlacements,_=D===void 0?{}:D,O=n.popupAlign,M=n.zIndex,L=n.stretch,A=n.getPopupClassNameFromAlign,B=n.fresh,k=n.alignPoint,j=n.onPopupClick,H=n.onPopupAlign,W=n.arrow,Y=n.popupMotion,K=n.maskMotion,q=n.popupTransitionName,ee=n.popupAnimation,Z=n.maskTransitionName,Q=n.maskAnimation,ne=n.className,ae=n.getTriggerDOMNode,J=Je(n,AA),re=P||N||!1,fe=f.exports.useState(!1),ve=G(fe,2),pe=ve[0],oe=ve[1];Nt(function(){oe(am())},[]);var se=f.exports.useRef({}),le=f.exports.useContext(mb),Ce=f.exports.useMemo(function(){return{registerSubPopup:function(tt,Vt){se.current[tt]=Vt,le==null||le.registerSubPopup(tt,Vt)}}},[le]),ce=Rw(),de=f.exports.useState(null),xe=G(de,2),he=xe[0],ke=xe[1],we=hn(function(je){Wu(je)&&he!==je&&ke(je),le==null||le.registerSubPopup(ce,je)}),ge=f.exports.useState(null),Pe=G(ge,2),Se=Pe[0],st=Pe[1],nt=f.exports.useRef(null),Ne=hn(function(je){Wu(je)&&Se!==je&&(st(je),nt.current=je)}),Ee=f.exports.Children.only(a),_e=(Ee==null?void 0:Ee.props)||{},Be={},qe=hn(function(je){var tt,Vt,nn=Se;return(nn==null?void 0:nn.contains(je))||((tt=Hu(nn))===null||tt===void 0?void 0:tt.host)===je||je===nn||(he==null?void 0:he.contains(je))||((Vt=Hu(he))===null||Vt===void 0?void 0:Vt.host)===je||je===he||Object.values(se.current).some(function(Ut){return(Ut==null?void 0:Ut.contains(je))||je===Ut})}),it=bb(i,Y,ee,q),ft=bb(i,K,Q,Z),ut=f.exports.useState(v||!1),Ue=G(ut,2),He=Ue[0],Xe=Ue[1],Le=d!=null?d:He,Re=hn(function(je){d===void 0&&Xe(je)});Nt(function(){Xe(d||!1)},[d]);var be=f.exports.useRef(Le);be.current=Le;var Ae=f.exports.useRef([]);Ae.current=[];var Me=hn(function(je){var tt;Re(je),((tt=Ae.current[Ae.current.length-1])!==null&&tt!==void 0?tt:Le)!==je&&(Ae.current.push(je),h==null||h(je))}),$e=f.exports.useRef(),Te=function(){clearTimeout($e.current)},ye=function(tt){var Vt=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;Te(),Vt===0?Me(tt):$e.current=setTimeout(function(){Me(tt)},Vt*1e3)};f.exports.useEffect(function(){return Te},[]);var Ge=f.exports.useState(!1),Ze=G(Ge,2),et=Ze[0],ht=Ze[1];Nt(function(je){(!je||Le)&&ht(!0)},[Le]);var mt=f.exports.useState(null),ct=G(mt,2),We=ct[0],Ve=ct[1],vt=f.exports.useState([0,0]),Ie=G(vt,2),ze=Ie[0],Ke=Ie[1],at=function(tt){Ke([tt.clientX,tt.clientY])},Gt=TA(Le,he,k?ze:Se,T,_,O,H),At=G(Gt,11),Zt=At[0],Jt=At[1],kn=At[2],qn=At[3],pn=At[4],Co=At[5],xo=At[6],In=At[7],wo=At[8],wr=At[9],Bn=At[10],sr=RA(pe,s,c,u),$r=G(sr,2),Ur=$r[0],Xn=$r[1],$o=Ur.has("click"),Er=Xn.has("click")||Xn.has("contextMenu"),bt=hn(function(){et||Bn()}),dt=function(){be.current&&k&&Er&&ye(!1)};NA(Le,Se,he,bt,dt),Nt(function(){bt()},[ze,T]),Nt(function(){Le&&!(_!=null&&_[T])&&bt()},[JSON.stringify(O)]);var Fe=f.exports.useMemo(function(){var je=PA(_,i,wr,k);return te(je,A==null?void 0:A(wr))},[wr,A,_,i,k]);f.exports.useImperativeHandle(r,function(){return{nativeElement:nt.current,forceAlign:bt}});var Ye=f.exports.useState(0),yt=G(Ye,2),Bt=yt[0],It=yt[1],Kt=f.exports.useState(0),sn=G(Kt,2),Pn=sn[0],cn=sn[1],Tn=function(){if(L&&Se){var tt=Se.getBoundingClientRect();It(tt.width),cn(tt.height)}},jn=function(){Tn(),bt()},Wi=function(tt){ht(!1),Bn(),g==null||g(tt)},iE=function(){return new Promise(function(tt){Tn(),Ve(function(){return tt})})};Nt(function(){We&&(Bn(),We(),Ve(null))},[We]);function un(je,tt,Vt,nn){Be[je]=function(Ut){var nc;nn==null||nn(Ut),ye(tt,Vt);for(var xf=arguments.length,km=new Array(xf>1?xf-1:0),rc=1;rc1?Vt-1:0),Ut=1;Ut1?Vt-1:0),Ut=1;Ut1&&arguments[1]!==void 0?arguments[1]:{},n=t.fieldNames,r=t.childrenAsData,o=[],i=Gw(n,!1),a=i.label,l=i.value,s=i.options,c=i.groupLabel;function u(d,v){!Array.isArray(d)||d.forEach(function(h){if(v||!(s in h)){var g=h[l];o.push({key:$b(h,o.length),groupOption:v,data:h,label:h[a],value:g})}else{var p=h[c];p===void 0&&r&&(p=h.label),o.push({key:$b(h,o.length),group:!0,data:h,label:p}),u(h[s],!0)}})}return u(e,!1),o}function bg(e){var t=U({},e);return"props"in t||Object.defineProperty(t,"props",{get:function(){return Mn(!1,"Return type is option instead of Option instance. Please read value directly instead of reading from `props`."),t}}),t}var jA=function(t,n,r){if(!n||!n.length)return null;var o=!1,i=function l(s,c){var u=kx(c),d=u[0],v=u.slice(1);if(!d)return[s];var h=s.split(d);return o=o||h.length>1,h.reduce(function(g,p){return[].concat(Oe(g),Oe(l(p,v)))},[]).filter(Boolean)},a=i(t,n);return o?typeof r<"u"?a.slice(0,r):a:null},lm=f.exports.createContext(null),HA=["id","prefixCls","className","showSearch","tagRender","direction","omitDomProps","displayValues","onDisplayValuesChange","emptyOptions","notFoundContent","onClear","mode","disabled","loading","getInputElement","getRawInputElement","open","defaultOpen","onDropdownVisibleChange","activeValue","onActiveValueChange","activeDescendantId","searchValue","autoClearSearchValue","onSearch","onSearchSplit","tokenSeparators","allowClear","suffixIcon","clearIcon","OptionList","animation","transitionName","dropdownStyle","dropdownClassName","dropdownMatchSelectWidth","dropdownRender","dropdownAlign","placement","builtinPlacements","getPopupContainer","showAction","onFocus","onBlur","onKeyUp","onKeyDown","onMouseDown"],WA=["value","onChange","removeIcon","placeholder","autoFocus","maxTagCount","maxTagTextLength","maxTagPlaceholder","choiceTransitionName","onInputKeyDown","onPopupScroll","tabIndex"],Sg=function(t){return t==="tags"||t==="multiple"},VA=f.exports.forwardRef(function(e,t){var n,r,o=e.id,i=e.prefixCls,a=e.className,l=e.showSearch,s=e.tagRender,c=e.direction,u=e.omitDomProps,d=e.displayValues,v=e.onDisplayValuesChange,h=e.emptyOptions,g=e.notFoundContent,p=g===void 0?"Not Found":g,b=e.onClear,m=e.mode,y=e.disabled,S=e.loading,x=e.getInputElement,$=e.getRawInputElement,E=e.open,w=e.defaultOpen,R=e.onDropdownVisibleChange,P=e.activeValue,N=e.onActiveValueChange,I=e.activeDescendantId,z=e.searchValue,F=e.autoClearSearchValue,T=e.onSearch,D=e.onSearchSplit,_=e.tokenSeparators,O=e.allowClear,M=e.suffixIcon,L=e.clearIcon,A=e.OptionList,B=e.animation,k=e.transitionName,j=e.dropdownStyle,H=e.dropdownClassName,W=e.dropdownMatchSelectWidth,Y=e.dropdownRender,K=e.dropdownAlign,q=e.placement,ee=e.builtinPlacements,Z=e.getPopupContainer,Q=e.showAction,ne=Q===void 0?[]:Q,ae=e.onFocus,J=e.onBlur,re=e.onKeyUp,fe=e.onKeyDown,ve=e.onMouseDown,pe=Je(e,HA),oe=Sg(m),se=(l!==void 0?l:oe)||m==="combobox",le=U({},pe);WA.forEach(function(Fe){delete le[Fe]}),u==null||u.forEach(function(Fe){delete le[Fe]});var Ce=f.exports.useState(!1),ce=G(Ce,2),de=ce[0],xe=ce[1];f.exports.useEffect(function(){xe(am())},[]);var he=f.exports.useRef(null),ke=f.exports.useRef(null),we=f.exports.useRef(null),ge=f.exports.useRef(null),Pe=f.exports.useRef(null),Se=f.exports.useRef(!1),st=Z_(),nt=G(st,3),Ne=nt[0],Ee=nt[1],_e=nt[2];f.exports.useImperativeHandle(t,function(){var Fe,Ye;return{focus:(Fe=ge.current)===null||Fe===void 0?void 0:Fe.focus,blur:(Ye=ge.current)===null||Ye===void 0?void 0:Ye.blur,scrollTo:function(Bt){var It;return(It=Pe.current)===null||It===void 0?void 0:It.scrollTo(Bt)}}});var Be=f.exports.useMemo(function(){var Fe;if(m!=="combobox")return z;var Ye=(Fe=d[0])===null||Fe===void 0?void 0:Fe.value;return typeof Ye=="string"||typeof Ye=="number"?String(Ye):""},[z,m,d]),qe=m==="combobox"&&typeof x=="function"&&x()||null,it=typeof $=="function"&&$(),ft=Fi(ke,it==null||(n=it.props)===null||n===void 0?void 0:n.ref),ut=f.exports.useState(!1),Ue=G(ut,2),He=Ue[0],Xe=Ue[1];Nt(function(){Xe(!0)},[]);var Le=kt(!1,{defaultValue:w,value:E}),Re=G(Le,2),be=Re[0],Ae=Re[1],Me=He?be:!1,$e=!p&&h;(y||$e&&Me&&m==="combobox")&&(Me=!1);var Te=$e?!1:Me,ye=f.exports.useCallback(function(Fe){var Ye=Fe!==void 0?Fe:!Me;y||(Ae(Ye),Me!==Ye&&(R==null||R(Ye)))},[y,Me,Ae,R]),Ge=f.exports.useMemo(function(){return(_||[]).some(function(Fe){return[` +`,`\r +`].includes(Fe)})},[_]),Ze=f.exports.useContext(lm)||{},et=Ze.maxCount,ht=Ze.rawValues,mt=function(Ye,yt,Bt){if(!((ht==null?void 0:ht.size)>=et)){var It=!0,Kt=Ye;N==null||N(null);var sn=jA(Ye,_,et&&et-ht.size),Pn=Bt?null:sn;return m!=="combobox"&&Pn&&(Kt="",D==null||D(Pn),ye(!1),It=!1),T&&Be!==Kt&&T(Kt,{source:yt?"typing":"effect"}),It}},ct=function(Ye){!Ye||!Ye.trim()||T(Ye,{source:"submit"})};f.exports.useEffect(function(){!Me&&!oe&&m!=="combobox"&&mt("",!1,!1)},[Me]),f.exports.useEffect(function(){be&&y&&Ae(!1),y&&!Se.current&&Ee(!1)},[y]);var We=Bw(),Ve=G(We,2),vt=Ve[0],Ie=Ve[1],ze=function(Ye){var yt=vt(),Bt=Ye.which;if(Bt===ue.ENTER&&(m!=="combobox"&&Ye.preventDefault(),Me||ye(!0)),Ie(!!Be),Bt===ue.BACKSPACE&&!yt&&oe&&!Be&&d.length){for(var It=Oe(d),Kt=null,sn=It.length-1;sn>=0;sn-=1){var Pn=It[sn];if(!Pn.disabled){It.splice(sn,1),Kt=Pn;break}}Kt&&v(It,{type:"remove",values:[Kt]})}for(var cn=arguments.length,Tn=new Array(cn>1?cn-1:0),jn=1;jn1?yt-1:0),It=1;It1?sn-1:0),cn=1;cn0&&arguments[0]!==void 0?arguments[0]:!1;u();var g=function(){l.current.forEach(function(b,m){if(b&&b.offsetParent){var y=ql(b),S=y.offsetHeight;s.current.get(m)!==S&&s.current.set(m,y.offsetHeight)}}),a(function(b){return b+1})};h?g():c.current=St(g)}function v(h,g){var p=e(h),b=l.current.get(p);g?(l.current.set(p,g),d()):l.current.delete(p),!b!=!g&&(g?t==null||t(h):n==null||n(h))}return f.exports.useEffect(function(){return u},[]),[v,d,s.current,i]}var qA=10;function XA(e,t,n,r,o,i,a,l){var s=f.exports.useRef(),c=f.exports.useState(null),u=G(c,2),d=u[0],v=u[1];return Nt(function(){if(d&&d.times=0;T-=1){var D=o(t[T]),_=n.get(D);if(_===void 0){y=!0;break}if(F-=_,F<=0)break}switch($){case"top":x=w-b;break;case"bottom":x=R-m+b;break;default:{var O=e.current.scrollTop,M=O+m;wM&&(S="bottom")}}x!==null&&a(x),x!==d.lastTop&&(y=!0)}y&&v(U(U({},d),{},{times:d.times+1,targetAlign:S,lastTop:x}))}},[d,e.current]),function(h){if(h==null){l();return}if(St.cancel(s.current),typeof h=="number")a(h);else if(h&&Qe(h)==="object"){var g,p=h.align;"index"in h?g=h.index:g=t.findIndex(function(y){return o(y)===h.key});var b=h.offset,m=b===void 0?0:b;v({times:0,index:g,offset:m,originAlign:p})}}}function QA(e,t,n){var r=e.length,o=t.length,i,a;if(r===0&&o===0)return null;r"u"?"undefined":Qe(navigator))==="object"&&/Firefox/i.test(navigator.userAgent);const qw=function(e,t){var n=f.exports.useRef(!1),r=f.exports.useRef(null);function o(){clearTimeout(r.current),n.current=!0,r.current=setTimeout(function(){n.current=!1},50)}var i=f.exports.useRef({top:e,bottom:t});return i.current.top=e,i.current.bottom=t,function(a){var l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,s=a<0&&i.current.top||a>0&&i.current.bottom;return l&&s?(clearTimeout(r.current),n.current=!1):(!s||n.current)&&o(),!n.current&&s}};function JA(e,t,n,r,o){var i=f.exports.useRef(0),a=f.exports.useRef(null),l=f.exports.useRef(null),s=f.exports.useRef(!1),c=qw(t,n);function u(b,m){St.cancel(a.current),i.current+=m,l.current=m,!c(m)&&(Ob||b.preventDefault(),a.current=St(function(){var y=s.current?10:1;o(i.current*y),i.current=0}))}function d(b,m){o(m,!0),Ob||b.preventDefault()}var v=f.exports.useRef(null),h=f.exports.useRef(null);function g(b){if(!!e){St.cancel(h.current),h.current=St(function(){v.current=null},2);var m=b.deltaX,y=b.deltaY,S=b.shiftKey,x=m,$=y;(v.current==="sx"||!v.current&&(S||!1)&&y&&!m)&&(x=y,$=0,v.current="sx");var E=Math.abs(x),w=Math.abs($);v.current===null&&(v.current=r&&E>w?"x":"y"),v.current==="y"?u(b,$):d(b,x)}}function p(b){!e||(s.current=b.detail===l.current)}return[g,p]}var e8=14/15;function t8(e,t,n){var r=f.exports.useRef(!1),o=f.exports.useRef(0),i=f.exports.useRef(null),a=f.exports.useRef(null),l,s=function(v){if(r.current){var h=Math.ceil(v.touches[0].pageY),g=o.current-h;o.current=h,n(g)&&v.preventDefault(),clearInterval(a.current),a.current=setInterval(function(){g*=e8,(!n(g,!0)||Math.abs(g)<=.1)&&clearInterval(a.current)},16)}},c=function(){r.current=!1,l()},u=function(v){l(),v.touches.length===1&&!r.current&&(r.current=!0,o.current=Math.ceil(v.touches[0].pageY),i.current=v.target,i.current.addEventListener("touchmove",s),i.current.addEventListener("touchend",c))};l=function(){i.current&&(i.current.removeEventListener("touchmove",s),i.current.removeEventListener("touchend",c))},Nt(function(){return e&&t.current.addEventListener("touchstart",u),function(){var d;(d=t.current)===null||d===void 0||d.removeEventListener("touchstart",u),l(),clearInterval(a.current)}},[e])}var n8=20;function Rb(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,n=e/t*e;return isNaN(n)&&(n=0),n=Math.max(n,n8),Math.floor(n)}function r8(e,t,n,r){var o=f.exports.useMemo(function(){return[new Map,[]]},[e,n.id,r]),i=G(o,2),a=i[0],l=i[1],s=function(u){var d=arguments.length>1&&arguments[1]!==void 0?arguments[1]:u,v=a.get(u),h=a.get(d);if(v===void 0||h===void 0)for(var g=e.length,p=l.length;pi||!!p),I=g==="rtl",z=te(r,V({},"".concat(r,"-rtl"),I),o),F=u||i8,T=f.exports.useRef(),D=f.exports.useRef(),_=f.exports.useState(0),O=G(_,2),M=O[0],L=O[1],A=f.exports.useState(0),B=G(A,2),k=B[0],j=B[1],H=f.exports.useState(!1),W=G(H,2),Y=W[0],K=W[1],q=function(){K(!0)},ee=function(){K(!1)},Z=f.exports.useCallback(function(Ie){return typeof v=="function"?v(Ie):Ie==null?void 0:Ie[v]},[v]),Q={getKey:Z};function ne(Ie){L(function(ze){var Ke;typeof Ie=="function"?Ke=Ie(ze):Ke=Ie;var at=ft(Ke);return T.current.scrollTop=at,at})}var ae=f.exports.useRef({start:0,end:F.length}),J=f.exports.useRef(),re=ZA(F,Z),fe=G(re,1),ve=fe[0];J.current=ve;var pe=KA(Z,null,null),oe=G(pe,4),se=oe[0],le=oe[1],Ce=oe[2],ce=oe[3],de=f.exports.useMemo(function(){if(!P)return{scrollHeight:void 0,start:0,end:F.length-1,offset:void 0};if(!N){var Ie;return{scrollHeight:((Ie=D.current)===null||Ie===void 0?void 0:Ie.offsetHeight)||0,start:0,end:F.length-1,offset:void 0}}for(var ze=0,Ke,at,Gt,At=F.length,Zt=0;Zt=M&&Ke===void 0&&(Ke=Zt,at=ze),pn>M+i&&Gt===void 0&&(Gt=Zt),ze=pn}return Ke===void 0&&(Ke=0,at=0,Gt=Math.ceil(i/a)),Gt===void 0&&(Gt=F.length-1),Gt=Math.min(Gt+1,F.length-1),{scrollHeight:ze,start:Ke,end:Gt,offset:at}},[N,P,M,F,ce,i]),xe=de.scrollHeight,he=de.start,ke=de.end,we=de.offset;ae.current.start=he,ae.current.end=ke;var ge=f.exports.useState({width:0,height:i}),Pe=G(ge,2),Se=Pe[0],st=Pe[1],nt=function(ze){st({width:ze.width||ze.offsetWidth,height:ze.height||ze.offsetHeight})},Ne=f.exports.useRef(),Ee=f.exports.useRef(),_e=f.exports.useMemo(function(){return Rb(Se.width,p)},[Se.width,p]),Be=f.exports.useMemo(function(){return Rb(Se.height,xe)},[Se.height,xe]),qe=xe-i,it=f.exports.useRef(qe);it.current=qe;function ft(Ie){var ze=Ie;return Number.isNaN(it.current)||(ze=Math.min(ze,it.current)),ze=Math.max(ze,0),ze}var ut=M<=0,Ue=M>=qe,He=qw(ut,Ue),Xe=function(){return{x:I?-k:k,y:M}},Le=f.exports.useRef(Xe()),Re=hn(function(){if(S){var Ie=Xe();(Le.current.x!==Ie.x||Le.current.y!==Ie.y)&&(S(Ie),Le.current=Ie)}});function be(Ie,ze){var Ke=Ie;ze?(Gn.exports.flushSync(function(){j(Ke)}),Re()):ne(Ke)}function Ae(Ie){var ze=Ie.currentTarget.scrollTop;ze!==M&&ne(ze),y==null||y(Ie),Re()}var Me=function(ze){var Ke=ze,at=p-Se.width;return Ke=Math.max(Ke,0),Ke=Math.min(Ke,at),Ke},$e=hn(function(Ie,ze){ze?(Gn.exports.flushSync(function(){j(function(Ke){var at=Ke+(I?-Ie:Ie);return Me(at)})}),Re()):ne(function(Ke){var at=Ke+Ie;return at})}),Te=JA(P,ut,Ue,!!p,$e),ye=G(Te,2),Ge=ye[0],Ze=ye[1];t8(P,T,function(Ie,ze){return He(Ie,ze)?!1:(Ge({preventDefault:function(){},deltaY:Ie}),!0)}),Nt(function(){function Ie(Ke){P&&Ke.preventDefault()}var ze=T.current;return ze.addEventListener("wheel",Ge),ze.addEventListener("DOMMouseScroll",Ze),ze.addEventListener("MozMousePixelScroll",Ie),function(){ze.removeEventListener("wheel",Ge),ze.removeEventListener("DOMMouseScroll",Ze),ze.removeEventListener("MozMousePixelScroll",Ie)}},[P]),Nt(function(){p&&j(function(Ie){return Me(Ie)})},[Se.width,p]);var et=function(){var ze,Ke;(ze=Ne.current)===null||ze===void 0||ze.delayHidden(),(Ke=Ee.current)===null||Ke===void 0||Ke.delayHidden()},ht=XA(T,F,Ce,a,Z,function(){return le(!0)},ne,et);f.exports.useImperativeHandle(t,function(){return{getScrollInfo:Xe,scrollTo:function(ze){function Ke(at){return at&&Qe(at)==="object"&&("left"in at||"top"in at)}Ke(ze)?(ze.left!==void 0&&j(Me(ze.left)),ht(ze.top)):ht(ze)}}}),Nt(function(){if(x){var Ie=F.slice(he,ke+1);x(Ie,F)}},[he,ke,F]);var mt=r8(F,Z,Ce,a),ct=E==null?void 0:E({start:he,end:ke,virtual:N,offsetX:k,offsetY:we,rtl:I,getSize:mt}),We=YA(F,he,ke,p,se,d,Q),Ve=null;i&&(Ve=U(V({},s?"height":"maxHeight",i),a8),P&&(Ve.overflowY="hidden",p&&(Ve.overflowX="hidden"),Y&&(Ve.pointerEvents="none")));var vt={};return I&&(vt.dir="rtl"),ie("div",{style:U(U({},c),{},{position:"relative"}),className:z,...vt,...R,children:[C(mr,{onResize:nt,children:C(m,{className:"".concat(r,"-holder"),style:Ve,ref:T,onScroll:Ae,onMouseEnter:et,children:C(Kw,{prefixCls:r,height:xe,offsetX:k,offsetY:we,scrollWidth:p,onInnerResize:le,ref:D,innerProps:$,rtl:I,extra:ct,children:We})})}),N&&xe>i&&C(Mb,{ref:Ne,prefixCls:r,scrollOffset:M,scrollRange:xe,rtl:I,onScroll:be,onStartMove:q,onStopMove:ee,spinSize:Be,containerSize:Se.height,style:w==null?void 0:w.verticalScrollBar,thumbStyle:w==null?void 0:w.verticalScrollBarThumb}),N&&p>Se.width&&C(Mb,{ref:Ee,prefixCls:r,scrollOffset:k,scrollRange:p,rtl:I,onScroll:be,onStartMove:q,onStopMove:ee,spinSize:_e,containerSize:Se.width,horizontal:!0,style:w==null?void 0:w.horizontalScrollBar,thumbStyle:w==null?void 0:w.horizontalScrollBarThumb})]})}var Xw=f.exports.forwardRef(l8);Xw.displayName="List";function s8(){return/(mac\sos|macintosh)/i.test(navigator.appVersion)}var c8=["disabled","title","children","style","className"];function Ib(e){return typeof e=="string"||typeof e=="number"}var u8=function(t,n){var r=Q_(),o=r.prefixCls,i=r.id,a=r.open,l=r.multiple,s=r.mode,c=r.searchValue,u=r.toggleOpen,d=r.notFoundContent,v=r.onPopupScroll,h=f.exports.useContext(lm),g=h.maxCount,p=h.flattenOptions,b=h.onActiveValue,m=h.defaultActiveFirstOption,y=h.onSelect,S=h.menuItemSelectedIcon,x=h.rawValues,$=h.fieldNames,E=h.virtual,w=h.direction,R=h.listHeight,P=h.listItemHeight,N=h.optionRender,I="".concat(o,"-item"),z=Hs(function(){return p},[a,p],function(Z,Q){return Q[0]&&Z[1]!==Q[1]}),F=f.exports.useRef(null),T=f.exports.useMemo(function(){return l&&typeof g<"u"&&(x==null?void 0:x.size)>=g},[l,g,x==null?void 0:x.size]),D=function(Q){Q.preventDefault()},_=function(Q){var ne;(ne=F.current)===null||ne===void 0||ne.scrollTo(typeof Q=="number"?{index:Q}:Q)},O=function(Q){for(var ne=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1,ae=z.length,J=0;J1&&arguments[1]!==void 0?arguments[1]:!1;B(Q);var ae={source:ne?"keyboard":"mouse"},J=z[Q];if(!J){b(null,-1,ae);return}b(J.value,Q,ae)};f.exports.useEffect(function(){k(m!==!1?O(0):-1)},[z.length,c]);var j=f.exports.useCallback(function(Z){return x.has(Z)&&s!=="combobox"},[s,Oe(x).toString(),x.size]);f.exports.useEffect(function(){var Z=setTimeout(function(){if(!l&&a&&x.size===1){var ne=Array.from(x)[0],ae=z.findIndex(function(J){var re=J.data;return re.value===ne});ae!==-1&&(k(ae),_(ae))}});if(a){var Q;(Q=F.current)===null||Q===void 0||Q.scrollTo(void 0)}return function(){return clearTimeout(Z)}},[a,c]);var H=function(Q){Q!==void 0&&y(Q,{selected:!x.has(Q)}),l||u(!1)};if(f.exports.useImperativeHandle(n,function(){return{onKeyDown:function(Q){var ne=Q.which,ae=Q.ctrlKey;switch(ne){case ue.N:case ue.P:case ue.UP:case ue.DOWN:{var J=0;if(ne===ue.UP?J=-1:ne===ue.DOWN?J=1:s8()&&ae&&(ne===ue.N?J=1:ne===ue.P&&(J=-1)),J!==0){var re=O(A+J,J);_(re),k(re,!0)}break}case ue.ENTER:{var fe,ve=z[A];ve&&!(ve!=null&&(fe=ve.data)!==null&&fe!==void 0&&fe.disabled)&&!T?H(ve.value):H(void 0),a&&Q.preventDefault();break}case ue.ESC:u(!1),a&&Q.stopPropagation()}},onKeyUp:function(){},scrollTo:function(Q){_(Q)}}}),z.length===0)return C("div",{role:"listbox",id:"".concat(i,"_list"),className:"".concat(I,"-empty"),onMouseDown:D,children:d});var W=Object.keys($).map(function(Z){return $[Z]}),Y=function(Q){return Q.label};function K(Z,Q){var ne=Z.group;return{role:ne?"presentation":"option",id:"".concat(i,"_list_").concat(Q)}}var q=function(Q){var ne=z[Q];if(!ne)return null;var ae=ne.data||{},J=ae.value,re=ne.group,fe=Ka(ae,!0),ve=Y(ne);return ne?f.exports.createElement("div",{"aria-label":typeof ve=="string"&&!re?ve:null,...fe,key:Q,...K(ne,Q),"aria-selected":j(J)},J):null},ee={role:"listbox",id:"".concat(i,"_list")};return ie(Tt,{children:[E&&ie("div",{...ee,style:{height:0,width:0,overflow:"hidden"},children:[q(A-1),q(A),q(A+1)]}),C(Xw,{itemKey:"key",ref:F,data:z,height:R,itemHeight:P,fullHeight:!1,onMouseDown:D,onScroll:v,virtual:E,direction:w,innerProps:E?null:ee,children:function(Z,Q){var ne,ae=Z.group,J=Z.groupOption,re=Z.data,fe=Z.label,ve=Z.value,pe=re.key;if(ae){var oe,se=(oe=re.title)!==null&&oe!==void 0?oe:Ib(fe)?fe.toString():void 0;return C("div",{className:te(I,"".concat(I,"-group")),title:se,children:fe!==void 0?fe:pe})}var le=re.disabled,Ce=re.title;re.children;var ce=re.style,de=re.className,xe=Je(re,c8),he=lr(xe,W),ke=j(ve),we=le||!ke&&T,ge="".concat(I,"-option"),Pe=te(I,ge,de,(ne={},V(ne,"".concat(ge,"-grouped"),J),V(ne,"".concat(ge,"-active"),A===Q&&!we),V(ne,"".concat(ge,"-disabled"),we),V(ne,"".concat(ge,"-selected"),ke),ne)),Se=Y(Z),st=!S||typeof S=="function"||ke,nt=typeof Se=="number"?Se:Se||ve,Ne=Ib(nt)?nt.toString():void 0;return Ce!==void 0&&(Ne=Ce),ie("div",{...Ka(he),...E?{}:K(Z,Q),"aria-selected":ke,className:Pe,title:Ne,onMouseMove:function(){A===Q||we||k(Q)},onClick:function(){we||H(ve)},style:ce,children:[C("div",{className:"".concat(ge,"-content"),children:typeof N=="function"?N(Z,{index:Q}):nt}),f.exports.isValidElement(S)||ke,st&&C(af,{className:"".concat(I,"-option-state"),customizeIcon:S,customizeIconProps:{value:ve,disabled:we,isSelected:ke},children:ke?"\u2713":null})]})}})]})},d8=f.exports.forwardRef(u8);const f8=function(e,t){var n=f.exports.useRef({values:new Map,options:new Map}),r=f.exports.useMemo(function(){var i=n.current,a=i.values,l=i.options,s=e.map(function(d){if(d.label===void 0){var v;return U(U({},d),{},{label:(v=a.get(d.value))===null||v===void 0?void 0:v.label})}return d}),c=new Map,u=new Map;return s.forEach(function(d){c.set(d.value,d),u.set(d.value,t.get(d.value)||l.get(d.value))}),n.current.values=c,n.current.options=u,s},[e,t]),o=f.exports.useCallback(function(i){return t.get(i)||n.current.options.get(i)},[t]);return[r,o]};function gv(e,t){return Uw(e).join("").toUpperCase().includes(t)}const v8=function(e,t,n,r,o){return f.exports.useMemo(function(){if(!n||r===!1)return e;var i=t.options,a=t.label,l=t.value,s=[],c=typeof r=="function",u=n.toUpperCase(),d=c?r:function(h,g){return o?gv(g[o],u):g[i]?gv(g[a!=="children"?a:"label"],u):gv(g[l],u)},v=c?function(h){return bg(h)}:function(h){return h};return e.forEach(function(h){if(h[i]){var g=d(n,v(h));if(g)s.push(h);else{var p=h[i].filter(function(b){return d(n,v(b))});p.length&&s.push(U(U({},h),{},V({},i,p)))}return}d(n,v(h))&&s.push(h)}),s},[e,r,o,n,t])};var Pb=0,p8=Rn();function g8(){var e;return p8?(e=Pb,Pb+=1):e="TEST_OR_SSR",e}function h8(e){var t=f.exports.useState(),n=G(t,2),r=n[0],o=n[1];return f.exports.useEffect(function(){o("rc_select_".concat(g8()))},[]),e||r}var m8=["children","value"],y8=["children"];function b8(e){var t=e,n=t.key,r=t.props,o=r.children,i=r.value,a=Je(r,m8);return U({key:n,value:i!==void 0?i:n,children:o},a)}function Qw(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;return Qo(e).map(function(n,r){if(!f.exports.isValidElement(n)||!n.type)return null;var o=n,i=o.type.isSelectOptGroup,a=o.key,l=o.props,s=l.children,c=Je(l,y8);return t||!i?b8(n):U(U({key:"__RC_SELECT_GRP__".concat(a===null?r:a,"__"),label:a},c),{},{options:Qw(s)})}).filter(function(n){return n})}var S8=function(t,n,r,o,i){return f.exports.useMemo(function(){var a=t,l=!t;l&&(a=Qw(n));var s=new Map,c=new Map,u=function(h,g,p){p&&typeof p=="string"&&h.set(g[p],g)},d=function v(h){for(var g=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,p=0;p2&&arguments[2]!==void 0?arguments[2]:{},Ge=ye.source,Ze=Ge===void 0?"keyboard":Ge;ut(Te),a&&r==="combobox"&&$e!==null&&Ze==="keyboard"&&Be(String($e))},[a,r]),Xe=function(Te,ye,Ge){var Ze=function(){var Ke,at=de(Te);return[M?{label:at==null?void 0:at[Y.label],value:Te,key:(Ke=at==null?void 0:at.key)!==null&&Ke!==void 0?Ke:Te}:Te,bg(at)]};if(ye&&h){var et=Ze(),ht=G(et,2),mt=ht[0],ct=ht[1];h(mt,ct)}else if(!ye&&g&&Ge!=="clear"){var We=Ze(),Ve=G(We,2),vt=Ve[0],Ie=Ve[1];g(vt,Ie)}},Le=Tb(function($e,Te){var ye,Ge=j?Te.selected:!0;Ge?ye=j?[].concat(Oe(ce),[$e]):[$e]:ye=ce.filter(function(Ze){return Ze.value!==$e}),nt(ye),Xe($e,Ge),r==="combobox"?Be(""):(!Sg||v)&&(Z(""),Be(""))}),Re=function(Te,ye){nt(Te);var Ge=ye.type,Ze=ye.values;(Ge==="remove"||Ge==="clear")&&Ze.forEach(function(et){Xe(et.value,!1,Ge)})},be=function(Te,ye){if(Z(Te),Be(null),ye.source==="submit"){var Ge=(Te||"").trim();if(Ge){var Ze=Array.from(new Set([].concat(Oe(he),[Ge])));nt(Ze),Xe(Ge,!0),Z("")}return}ye.source!=="blur"&&(r==="combobox"&&nt(Te),u==null||u(Te))},Ae=function(Te){var ye=Te;r!=="tags"&&(ye=Te.map(function(Ze){var et=ae.get(Ze);return et==null?void 0:et.value}).filter(function(Ze){return Ze!==void 0}));var Ge=Array.from(new Set([].concat(Oe(he),Oe(ye))));nt(Ge),Ge.forEach(function(Ze){Xe(Ze,!0)})},Me=f.exports.useMemo(function(){var $e=N!==!1&&b!==!1;return U(U({},Q),{},{flattenOptions:st,onActiveValue:He,defaultActiveFirstOption:Ue,onSelect:Le,menuItemSelectedIcon:P,rawValues:he,fieldNames:Y,virtual:$e,direction:I,listHeight:F,listItemHeight:D,childrenAsData:H,maxCount:A,optionRender:E})},[A,Q,st,He,Ue,Le,P,he,Y,N,b,I,F,D,H,E]);return C(lm.Provider,{value:Me,children:C(VA,{...B,id:k,prefixCls:i,ref:t,omitDomProps:x8,mode:r,displayValues:xe,onDisplayValuesChange:Re,direction:I,searchValue:ee,onSearch:be,autoClearSearchValue:v,onSearchSplit:Ae,dropdownMatchSelectWidth:b,OptionList:d8,emptyOptions:!st.length,activeValue:_e,activeDescendantId:"".concat(k,"_list_").concat(ft)})})}),um=$8;um.Option=cm;um.OptGroup=sm;function ed(e,t,n){return te({[`${e}-status-success`]:t==="success",[`${e}-status-warning`]:t==="warning",[`${e}-status-error`]:t==="error",[`${e}-status-validating`]:t==="validating",[`${e}-has-feedback`]:n})}const dm=(e,t)=>t||e,E8=()=>{const[,e]=Kn(),n=new Mt(e.colorBgBase).toHsl().l<.5?{opacity:.65}:{};return C("svg",{style:n,width:"184",height:"152",viewBox:"0 0 184 152",xmlns:"http://www.w3.org/2000/svg",children:ie("g",{fill:"none",fillRule:"evenodd",children:[ie("g",{transform:"translate(24 31.67)",children:[C("ellipse",{fillOpacity:".8",fill:"#F5F5F7",cx:"67.797",cy:"106.89",rx:"67.797",ry:"12.668"}),C("path",{d:"M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z",fill:"#AEB8C2"}),C("path",{d:"M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z",fill:"url(#linearGradient-1)",transform:"translate(13.56)"}),C("path",{d:"M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z",fill:"#F5F5F7"}),C("path",{d:"M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z",fill:"#DCE0E6"})]}),C("path",{d:"M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z",fill:"#DCE0E6"}),ie("g",{transform:"translate(149.65 15.383)",fill:"#FFF",children:[C("ellipse",{cx:"20.654",cy:"3.167",rx:"2.849",ry:"2.815"}),C("path",{d:"M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"})]})]})})},M8=E8,O8=()=>{const[,e]=Kn(),{colorFill:t,colorFillTertiary:n,colorFillQuaternary:r,colorBgContainer:o}=e,{borderColor:i,shadowColor:a,contentColor:l}=f.exports.useMemo(()=>({borderColor:new Mt(t).onBackground(o).toHexShortString(),shadowColor:new Mt(n).onBackground(o).toHexShortString(),contentColor:new Mt(r).onBackground(o).toHexShortString()}),[t,n,r,o]);return C("svg",{width:"64",height:"41",viewBox:"0 0 64 41",xmlns:"http://www.w3.org/2000/svg",children:ie("g",{transform:"translate(0 1)",fill:"none",fillRule:"evenodd",children:[C("ellipse",{fill:a,cx:"32",cy:"33",rx:"32",ry:"7"}),ie("g",{fillRule:"nonzero",stroke:i,children:[C("path",{d:"M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"}),C("path",{d:"M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z",fill:l})]})]})})},R8=O8,I8=e=>{const{componentCls:t,margin:n,marginXS:r,marginXL:o,fontSize:i,lineHeight:a}=e;return{[t]:{marginInline:r,fontSize:i,lineHeight:a,textAlign:"center",[`${t}-image`]:{height:e.emptyImgHeight,marginBottom:r,opacity:e.opacityImage,img:{height:"100%"},svg:{maxWidth:"100%",height:"100%",margin:"auto"}},[`${t}-description`]:{color:e.colorText},[`${t}-footer`]:{marginTop:n},"&-normal":{marginBlock:o,color:e.colorTextDisabled,[`${t}-description`]:{color:e.colorTextDisabled},[`${t}-image`]:{height:e.emptyImgHeightMD}},"&-small":{marginBlock:r,color:e.colorTextDisabled,[`${t}-image`]:{height:e.emptyImgHeightSM}}}}},P8=vn("Empty",e=>{const{componentCls:t,controlHeightLG:n,calc:r}=e,o=$t(e,{emptyImgCls:`${t}-img`,emptyImgHeight:r(n).mul(2.5).equal(),emptyImgHeightMD:n,emptyImgHeightSM:r(n).mul(.875).equal()});return[I8(o)]});var T8=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var{className:t,rootClassName:n,prefixCls:r,image:o=Zw,description:i,children:a,imageStyle:l,style:s}=e,c=T8(e,["className","rootClassName","prefixCls","image","description","children","imageStyle","style"]);const{getPrefixCls:u,direction:d,empty:v}=f.exports.useContext(ot),h=u("empty",r),[g,p,b]=P8(h),[m]=Wx("Empty"),y=typeof i<"u"?i:m==null?void 0:m.description,S=typeof y=="string"?y:"empty";let x=null;return typeof o=="string"?x=C("img",{alt:S,src:o}):x=o,g(ie("div",{...Object.assign({className:te(p,b,h,v==null?void 0:v.className,{[`${h}-normal`]:o===Jw,[`${h}-rtl`]:d==="rtl"},t,n),style:Object.assign(Object.assign({},v==null?void 0:v.style),s)},c),children:[C("div",{className:`${h}-image`,style:l,children:x}),y&&C("div",{className:`${h}-description`,children:y}),a&&C("div",{className:`${h}-footer`,children:a})]}))};fm.PRESENTED_IMAGE_DEFAULT=Zw;fm.PRESENTED_IMAGE_SIMPLE=Jw;const wl=fm,N8=e=>{const{componentName:t}=e,{getPrefixCls:n}=f.exports.useContext(ot),r=n("empty");switch(t){case"Table":case"List":return C(wl,{image:wl.PRESENTED_IMAGE_SIMPLE});case"Select":case"TreeSelect":case"Cascader":case"Transfer":case"Mentions":return C(wl,{image:wl.PRESENTED_IMAGE_SIMPLE,className:`${r}-small`});default:return C(wl,{})}},_8=N8,A8=["outlined","borderless","filled"],D8=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:void 0;const n=f.exports.useContext(v_);let r;typeof e<"u"?r=e:t===!1?r="borderless":r=n!=null?n:"outlined";const o=A8.includes(r);return[r,o]},vm=D8,L8=e=>{const n={overflow:{adjustX:!0,adjustY:!0,shiftY:!0},htmlRegion:e==="scroll"?"scroll":"visible",dynamicInset:!0};return{bottomLeft:Object.assign(Object.assign({},n),{points:["tl","bl"],offset:[0,4]}),bottomRight:Object.assign(Object.assign({},n),{points:["tr","br"],offset:[0,4]}),topLeft:Object.assign(Object.assign({},n),{points:["bl","tl"],offset:[0,-4]}),topRight:Object.assign(Object.assign({},n),{points:["br","tr"],offset:[0,-4]})}};function z8(e,t){return e||L8(t)}const Nb=e=>{const{optionHeight:t,optionFontSize:n,optionLineHeight:r,optionPadding:o}=e;return{position:"relative",display:"block",minHeight:t,padding:o,color:e.colorText,fontWeight:"normal",fontSize:n,lineHeight:r,boxSizing:"border-box"}},F8=e=>{const{antCls:t,componentCls:n}=e,r=`${n}-item`,o=`&${t}-slide-up-enter${t}-slide-up-enter-active`,i=`&${t}-slide-up-appear${t}-slide-up-appear-active`,a=`&${t}-slide-up-leave${t}-slide-up-leave-active`,l=`${n}-dropdown-placement-`;return[{[`${n}-dropdown`]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",top:-9999,zIndex:e.zIndexPopup,boxSizing:"border-box",padding:e.paddingXXS,overflow:"hidden",fontSize:e.fontSize,fontVariant:"initial",backgroundColor:e.colorBgElevated,borderRadius:e.borderRadiusLG,outline:"none",boxShadow:e.boxShadowSecondary,[` + ${o}${l}bottomLeft, + ${i}${l}bottomLeft + `]:{animationName:nm},[` + ${o}${l}topLeft, + ${i}${l}topLeft, + ${o}${l}topRight, + ${i}${l}topRight + `]:{animationName:om},[`${a}${l}bottomLeft`]:{animationName:rm},[` + ${a}${l}topLeft, + ${a}${l}topRight + `]:{animationName:im},"&-hidden":{display:"none"},[`${r}`]:Object.assign(Object.assign({},Nb(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},ei),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${r}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${r}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${r}-option-state`]:{color:e.colorPrimary},[`&:has(+ ${r}-option-selected:not(${r}-option-disabled))`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${r}-option-selected:not(${r}-option-disabled)`]:{borderStartStartRadius:0,borderStartEndRadius:0}}},"&-disabled":{[`&${r}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},Nb(e)),{color:e.colorTextDisabled})}),"&-rtl":{direction:"rtl"}})},Xa(e,"slide-up"),Xa(e,"slide-down"),Zu(e,"move-up"),Zu(e,"move-down")]},k8=F8,Qi=2,B8=e=>{const{multipleSelectItemHeight:t,selectHeight:n,lineWidth:r}=e;return e.calc(n).sub(t).div(2).sub(r).equal()},pm=(e,t)=>{const{componentCls:n,iconCls:r}=e,o=`${n}-selection-overflow`,i=e.multipleSelectItemHeight,a=B8(e),l=t?`${n}-${t}`:"";return{[`${n}-multiple${l}`]:{[o]:{position:"relative",display:"flex",flex:"auto",flexWrap:"wrap",maxWidth:"100%","&-item":{flex:"none",alignSelf:"center",maxWidth:"100%",display:"inline-flex"}},[`${n}-selector`]:{display:"flex",flexWrap:"wrap",alignItems:"center",height:"100%",paddingInline:e.calc(Qi).mul(2).equal(),paddingBlock:e.calc(a).sub(Qi).equal(),borderRadius:e.borderRadius,[`${n}-disabled&`]:{background:e.multipleSelectorBgDisabled,cursor:"not-allowed"},"&:after":{display:"inline-block",width:0,margin:`${X(Qi)} 0`,lineHeight:X(i),visibility:"hidden",content:'"\\a0"'}},[`${n}-selection-item`]:{display:"flex",alignSelf:"center",flex:"none",boxSizing:"border-box",maxWidth:"100%",height:i,marginTop:Qi,marginBottom:Qi,lineHeight:X(e.calc(i).sub(e.calc(e.lineWidth).mul(2)).equal()),borderRadius:e.borderRadiusSM,cursor:"default",transition:`font-size ${e.motionDurationSlow}, line-height ${e.motionDurationSlow}, height ${e.motionDurationSlow}`,marginInlineEnd:e.calc(Qi).mul(2).equal(),paddingInlineStart:e.paddingXS,paddingInlineEnd:e.calc(e.paddingXS).div(2).equal(),[`${n}-disabled&`]:{color:e.multipleItemColorDisabled,borderColor:e.multipleItemBorderColorDisabled,cursor:"not-allowed"},"&-content":{display:"inline-block",marginInlineEnd:e.calc(e.paddingXS).div(2).equal(),overflow:"hidden",whiteSpace:"pre",textOverflow:"ellipsis"},"&-remove":Object.assign(Object.assign({},Uh()),{display:"inline-flex",alignItems:"center",color:e.colorIcon,fontWeight:"bold",fontSize:10,lineHeight:"inherit",cursor:"pointer",[`> ${r}`]:{verticalAlign:"-0.2em"},"&:hover":{color:e.colorIconHover}})},[`${o}-item + ${o}-item`]:{[`${n}-selection-search`]:{marginInlineStart:0}},[`${o}-item-suffix`]:{height:"100%"},[`${n}-selection-search`]:{display:"inline-flex",position:"relative",maxWidth:"100%",marginInlineStart:e.calc(e.inputPaddingHorizontalBase).sub(a).equal(),[` + &-input, + &-mirror + `]:{height:i,fontFamily:e.fontFamily,lineHeight:X(i),transition:`all ${e.motionDurationSlow}`},"&-input":{width:"100%",minWidth:4.1},"&-mirror":{position:"absolute",top:0,insetInlineStart:0,insetInlineEnd:"auto",zIndex:999,whiteSpace:"pre",visibility:"hidden"}},[`${n}-selection-placeholder`]:{position:"absolute",top:"50%",insetInlineStart:e.inputPaddingHorizontalBase,insetInlineEnd:e.inputPaddingHorizontalBase,transform:"translateY(-50%)",transition:`all ${e.motionDurationSlow}`}}}};function hv(e,t){const{componentCls:n}=e,r=t?`${n}-${t}`:"",o={[`${n}-multiple${r}`]:{fontSize:e.fontSize,[`${n}-selector`]:{[`${n}-show-search&`]:{cursor:"text"}},[` + &${n}-show-arrow ${n}-selector, + &${n}-allow-clear ${n}-selector + `]:{paddingInlineEnd:e.calc(e.fontSizeIcon).add(e.controlPaddingHorizontal).equal()}}};return[pm(e,t),o]}const j8=e=>{const{componentCls:t}=e,n=$t(e,{selectHeight:e.controlHeightSM,multipleSelectItemHeight:e.controlHeightXS,borderRadius:e.borderRadiusSM,borderRadiusSM:e.borderRadiusXS}),r=$t(e,{fontSize:e.fontSizeLG,selectHeight:e.controlHeightLG,multipleSelectItemHeight:e.multipleItemHeightLG,borderRadius:e.borderRadiusLG,borderRadiusSM:e.borderRadius});return[hv(e),hv(n,"sm"),{[`${t}-multiple${t}-sm`]:{[`${t}-selection-placeholder`]:{insetInline:e.calc(e.controlPaddingHorizontalSM).sub(e.lineWidth).equal()},[`${t}-selection-search`]:{marginInlineStart:2}}},hv(r,"lg")]};function mv(e,t){const{componentCls:n,inputPaddingHorizontalBase:r,borderRadius:o}=e,i=e.calc(e.controlHeight).sub(e.calc(e.lineWidth).mul(2)).equal(),a=t?`${n}-${t}`:"";return{[`${n}-single${a}`]:{fontSize:e.fontSize,height:e.controlHeight,[`${n}-selector`]:Object.assign(Object.assign({},Qt(e,!0)),{display:"flex",borderRadius:o,[`${n}-selection-search`]:{position:"absolute",top:0,insetInlineStart:r,insetInlineEnd:r,bottom:0,"&-input":{width:"100%",WebkitAppearance:"textfield"}},[` + ${n}-selection-item, + ${n}-selection-placeholder + `]:{padding:0,lineHeight:X(i),transition:`all ${e.motionDurationSlow}, visibility 0s`,alignSelf:"center"},[`${n}-selection-placeholder`]:{transition:"none",pointerEvents:"none"},[["&:after",`${n}-selection-item:empty:after`,`${n}-selection-placeholder:empty:after`].join(",")]:{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'}}),[` + &${n}-show-arrow ${n}-selection-item, + &${n}-show-arrow ${n}-selection-placeholder + `]:{paddingInlineEnd:e.showArrowPaddingInlineEnd},[`&${n}-open ${n}-selection-item`]:{color:e.colorTextPlaceholder},[`&:not(${n}-customize-input)`]:{[`${n}-selector`]:{width:"100%",height:"100%",padding:`0 ${X(r)}`,[`${n}-selection-search-input`]:{height:i},"&:after":{lineHeight:X(i)}}},[`&${n}-customize-input`]:{[`${n}-selector`]:{"&:after":{display:"none"},[`${n}-selection-search`]:{position:"static",width:"100%"},[`${n}-selection-placeholder`]:{position:"absolute",insetInlineStart:0,insetInlineEnd:0,padding:`0 ${X(r)}`,"&:after":{display:"none"}}}}}}}function H8(e){const{componentCls:t}=e,n=e.calc(e.controlPaddingHorizontalSM).sub(e.lineWidth).equal();return[mv(e),mv($t(e,{controlHeight:e.controlHeightSM,borderRadius:e.borderRadiusSM}),"sm"),{[`${t}-single${t}-sm`]:{[`&:not(${t}-customize-input)`]:{[`${t}-selection-search`]:{insetInlineStart:n,insetInlineEnd:n},[`${t}-selector`]:{padding:`0 ${X(n)}`},[`&${t}-show-arrow ${t}-selection-search`]:{insetInlineEnd:e.calc(n).add(e.calc(e.fontSize).mul(1.5)).equal()},[` + &${t}-show-arrow ${t}-selection-item, + &${t}-show-arrow ${t}-selection-placeholder + `]:{paddingInlineEnd:e.calc(e.fontSize).mul(1.5).equal()}}}},mv($t(e,{controlHeight:e.singleItemHeightLG,fontSize:e.fontSizeLG,borderRadius:e.borderRadiusLG}),"lg")]}const W8=e=>{const{fontSize:t,lineHeight:n,controlHeight:r,controlPaddingHorizontal:o,zIndexPopupBase:i,colorText:a,fontWeightStrong:l,controlItemBgActive:s,controlItemBgHover:c,colorBgContainer:u,colorFillSecondary:d,controlHeightLG:v,controlHeightSM:h,colorBgContainerDisabled:g,colorTextDisabled:p}=e;return{zIndexPopup:i+50,optionSelectedColor:a,optionSelectedFontWeight:l,optionSelectedBg:s,optionActiveBg:c,optionPadding:`${(r-t*n)/2}px ${o}px`,optionFontSize:t,optionLineHeight:n,optionHeight:r,selectorBg:u,clearBg:u,singleItemHeightLG:v,multipleItemBg:d,multipleItemBorderColor:"transparent",multipleItemHeight:h,multipleItemHeightLG:r,multipleSelectorBgDisabled:g,multipleItemColorDisabled:p,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(e.fontSize*1.25)}},e2=(e,t)=>{const{componentCls:n,antCls:r,controlOutlineWidth:o}=e;return{[`&:not(${n}-customize-input) ${n}-selector`]:{border:`${X(e.lineWidth)} ${e.lineType} ${t.borderColor}`,background:e.selectorBg},[`&:not(${n}-disabled):not(${n}-customize-input):not(${r}-pagination-size-changer)`]:{[`&:hover ${n}-selector`]:{borderColor:t.hoverBorderHover},[`${n}-focused& ${n}-selector`]:{borderColor:t.activeBorderColor,boxShadow:`0 0 0 ${X(o)} ${t.activeShadowColor}`,outline:0}}}},_b=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},e2(e,t))}),V8=e=>({"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},e2(e,{borderColor:e.colorBorder,hoverBorderHover:e.colorPrimaryHover,activeBorderColor:e.colorPrimary,activeShadowColor:e.controlOutline})),_b(e,{status:"error",borderColor:e.colorError,hoverBorderHover:e.colorErrorHover,activeBorderColor:e.colorError,activeShadowColor:e.colorErrorOutline})),_b(e,{status:"warning",borderColor:e.colorWarning,hoverBorderHover:e.colorWarningHover,activeBorderColor:e.colorWarning,activeShadowColor:e.colorWarningOutline})),{[`&${e.componentCls}-disabled`]:{[`&:not(${e.componentCls}-customize-input) ${e.componentCls}-selector`]:{background:e.colorBgContainerDisabled,color:e.colorTextDisabled}},[`&${e.componentCls}-multiple ${e.componentCls}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}})}),t2=(e,t)=>{const{componentCls:n,antCls:r}=e;return{[`&:not(${n}-customize-input) ${n}-selector`]:{background:t.bg,border:`${X(e.lineWidth)} ${e.lineType} transparent`,color:t.color},[`&:not(${n}-disabled):not(${n}-customize-input):not(${r}-pagination-size-changer)`]:{[`&:hover ${n}-selector`]:{background:t.hoverBg},[`${n}-focused& ${n}-selector`]:{background:e.selectorBg,borderColor:t.activeBorderColor,outline:0}}}},Ab=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},t2(e,t))}),U8=e=>({"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},t2(e,{bg:e.colorFillTertiary,hoverBg:e.colorFillSecondary,activeBorderColor:e.colorPrimary,color:e.colorText})),Ab(e,{status:"error",bg:e.colorErrorBg,hoverBg:e.colorErrorBgHover,activeBorderColor:e.colorError,color:e.colorError})),Ab(e,{status:"warning",bg:e.colorWarningBg,hoverBg:e.colorWarningBgHover,activeBorderColor:e.colorWarning,color:e.colorWarning})),{[`&${e.componentCls}-disabled`]:{[`&:not(${e.componentCls}-customize-input) ${e.componentCls}-selector`]:{borderColor:e.colorBorder,background:e.colorBgContainerDisabled,color:e.colorTextDisabled}},[`&${e.componentCls}-multiple ${e.componentCls}-selection-item`]:{background:e.colorBgContainer,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`}})}),Y8=e=>({"&-borderless":{[`${e.componentCls}-selector`]:{background:"transparent",borderColor:"transparent"},[`&${e.componentCls}-disabled`]:{[`&:not(${e.componentCls}-customize-input) ${e.componentCls}-selector`]:{color:e.colorTextDisabled}},[`&${e.componentCls}-multiple ${e.componentCls}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}}}),G8=e=>({[e.componentCls]:Object.assign(Object.assign(Object.assign({},V8(e)),U8(e)),Y8(e))}),K8=G8,q8=e=>{const{componentCls:t}=e;return{position:"relative",transition:`all ${e.motionDurationMid} ${e.motionEaseInOut}`,input:{cursor:"pointer"},[`${t}-show-search&`]:{cursor:"text",input:{cursor:"auto",color:"inherit",height:"100%"}},[`${t}-disabled&`]:{cursor:"not-allowed",input:{cursor:"not-allowed"}}}},X8=e=>{const{componentCls:t}=e;return{[`${t}-selection-search-input`]:{margin:0,padding:0,background:"transparent",border:"none",outline:"none",appearance:"none",fontFamily:"inherit","&::-webkit-search-cancel-button":{display:"none","-webkit-appearance":"none"}}}},Q8=e=>{const{antCls:t,componentCls:n,inputPaddingHorizontalBase:r,iconCls:o}=e;return{[n]:Object.assign(Object.assign({},Qt(e)),{position:"relative",display:"inline-block",cursor:"pointer",[`&:not(${n}-customize-input) ${n}-selector`]:Object.assign(Object.assign({},q8(e)),X8(e)),[`${n}-selection-item`]:Object.assign(Object.assign({flex:1,fontWeight:"normal",position:"relative",userSelect:"none"},ei),{[`> ${t}-typography`]:{display:"inline"}}),[`${n}-selection-placeholder`]:Object.assign(Object.assign({},ei),{flex:1,color:e.colorTextPlaceholder,pointerEvents:"none"}),[`${n}-arrow`]:Object.assign(Object.assign({},Uh()),{position:"absolute",top:"50%",insetInlineStart:"auto",insetInlineEnd:r,height:e.fontSizeIcon,marginTop:e.calc(e.fontSizeIcon).mul(-1).div(2).equal(),color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,lineHeight:1,textAlign:"center",pointerEvents:"none",display:"flex",alignItems:"center",transition:`opacity ${e.motionDurationSlow} ease`,[o]:{verticalAlign:"top",transition:`transform ${e.motionDurationSlow}`,"> svg":{verticalAlign:"top"},[`&:not(${n}-suffix)`]:{pointerEvents:"auto"}},[`${n}-disabled &`]:{cursor:"not-allowed"},"> *:not(:last-child)":{marginInlineEnd:8}}),[`${n}-clear`]:{position:"absolute",top:"50%",insetInlineStart:"auto",insetInlineEnd:r,zIndex:1,display:"inline-block",width:e.fontSizeIcon,height:e.fontSizeIcon,marginTop:e.calc(e.fontSizeIcon).mul(-1).div(2).equal(),color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,fontStyle:"normal",lineHeight:1,textAlign:"center",textTransform:"none",cursor:"pointer",opacity:0,transition:`color ${e.motionDurationMid} ease, opacity ${e.motionDurationSlow} ease`,textRendering:"auto","&:before":{display:"block"},"&:hover":{color:e.colorTextTertiary}},"&:hover":{[`${n}-clear`]:{opacity:1},[`${n}-arrow:not(:last-child)`]:{opacity:0}}}),[`${n}-has-feedback`]:{[`${n}-clear`]:{insetInlineEnd:e.calc(r).add(e.fontSize).add(e.paddingXS).equal()}}}},Z8=e=>{const{componentCls:t}=e;return[{[t]:{[`&${t}-in-form-item`]:{width:"100%"}}},Q8(e),H8(e),j8(e),k8(e),{[`${t}-rtl`]:{direction:"rtl"}},tf(e,{borderElCls:`${t}-selector`,focusElCls:`${t}-focused`})]},J8=vn("Select",(e,t)=>{let{rootPrefixCls:n}=t;const r=$t(e,{rootPrefixCls:n,inputPaddingHorizontalBase:e.calc(e.paddingSM).sub(1).equal(),multipleSelectItemHeight:e.multipleItemHeight,selectHeight:e.controlHeight});return[Z8(r),K8(r)]},W8,{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});function eD(e){let{suffixIcon:t,clearIcon:n,menuItemSelectedIcon:r,removeIcon:o,loading:i,multiple:a,hasFeedback:l,prefixCls:s,showSuffixIcon:c,feedbackIcon:u,showArrow:d,componentName:v}=e;const h=n!=null?n:C(Nd,{}),g=y=>t===null&&!l&&!d?null:ie(Tt,{children:[c!==!1&&y,l&&u]});let p=null;if(t!==void 0)p=g(t);else if(i)p=g(C(ux,{spin:!0}));else{const y=`${s}-suffix`;p=S=>{let{open:x,showSearch:$}=S;return g(x&&$?C(_d,{className:y}):C(qI,{className:y}))}}let b=null;r!==void 0?b=r:a?b=C(lx,{}):b=null;let m=null;return o!==void 0?m=o:m=C(eo,{}),{clearIcon:h,suffixIcon:p,itemIcon:b,removeIcon:m}}function tD(e,t){return t!==void 0?t:e!==null}var nD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n;const{prefixCls:r,bordered:o,className:i,rootClassName:a,getPopupContainer:l,popupClassName:s,dropdownClassName:c,listHeight:u=256,placement:d,listItemHeight:v,size:h,disabled:g,notFoundContent:p,status:b,builtinPlacements:m,dropdownMatchSelectWidth:y,popupMatchSelectWidth:S,direction:x,style:$,allowClear:E,variant:w,dropdownStyle:R,transitionName:P,tagRender:N,maxCount:I}=e,z=nD(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount"]),{getPopupContainer:F,getPrefixCls:T,renderEmpty:D,direction:_,virtual:O,popupMatchSelectWidth:M,popupOverflow:L,select:A}=f.exports.useContext(ot),[,B]=Kn(),k=v!=null?v:B==null?void 0:B.controlHeight,j=T("select",r),H=T(),W=x!=null?x:_,{compactSize:Y,compactItemClassnames:K}=ef(j,W),[q,ee]=vm(w,o),Z=no(j),[Q,ne,ae]=J8(j,Z),J=f.exports.useMemo(()=>{const{mode:Be}=e;if(Be!=="combobox")return Be===n2?"combobox":Be},[e.mode]),re=J==="multiple"||J==="tags",fe=tD(e.suffixIcon,e.showArrow),ve=(n=S!=null?S:y)!==null&&n!==void 0?n:M,{status:pe,hasFeedback:oe,isFormItemInput:se,feedbackIcon:le}=f.exports.useContext(Jr),Ce=dm(pe,b);let ce;p!==void 0?ce=p:J==="combobox"?ce=null:ce=(D==null?void 0:D("Select"))||C(_8,{componentName:"Select"});const{suffixIcon:de,itemIcon:xe,removeIcon:he,clearIcon:ke}=eD(Object.assign(Object.assign({},z),{multiple:re,hasFeedback:oe,feedbackIcon:le,showSuffixIcon:fe,prefixCls:j,componentName:"Select"})),we=E===!0?{clearIcon:ke}:E,ge=lr(z,["suffixIcon","itemIcon"]),Pe=te(s||c,{[`${j}-dropdown-${W}`]:W==="rtl"},a,ae,Z,ne),Se=So(Be=>{var qe;return(qe=h!=null?h:Y)!==null&&qe!==void 0?qe:Be}),st=f.exports.useContext(rl),nt=g!=null?g:st,Ne=te({[`${j}-lg`]:Se==="large",[`${j}-sm`]:Se==="small",[`${j}-rtl`]:W==="rtl",[`${j}-${q}`]:ee,[`${j}-in-form-item`]:se},ed(j,Ce,oe),K,A==null?void 0:A.className,i,a,ae,Z,ne),Ee=f.exports.useMemo(()=>d!==void 0?d:W==="rtl"?"bottomRight":"bottomLeft",[d,W]),[_e]=Qd("SelectLike",R==null?void 0:R.zIndex);return Q(C(um,{...Object.assign({ref:t,virtual:O,showSearch:A==null?void 0:A.showSearch},ge,{style:Object.assign(Object.assign({},A==null?void 0:A.style),$),dropdownMatchSelectWidth:ve,transitionName:ni(H,"slide-up",P),builtinPlacements:z8(m,L),listHeight:u,listItemHeight:k,mode:J,prefixCls:j,placement:Ee,direction:W,suffixIcon:de,menuItemSelectedIcon:xe,removeIcon:he,allowClear:we,notFoundContent:ce,className:Ne,getPopupContainer:l||F,dropdownClassName:Pe,disabled:nt,dropdownStyle:Object.assign(Object.assign({},R),{zIndex:_e}),maxCount:re?I:void 0,tagRender:re?N:void 0})}))},ol=f.exports.forwardRef(rD),oD=q_(ol);ol.SECRET_COMBOBOX_MODE_DO_NOT_USE=n2;ol.Option=cm;ol.OptGroup=sm;ol._InternalPanelDoNotUseOrYouWillBeFired=oD;const r2=ol,o2=["xxl","xl","lg","md","sm","xs"],iD=e=>({xs:`(max-width: ${e.screenXSMax}px)`,sm:`(min-width: ${e.screenSM}px)`,md:`(min-width: ${e.screenMD}px)`,lg:`(min-width: ${e.screenLG}px)`,xl:`(min-width: ${e.screenXL}px)`,xxl:`(min-width: ${e.screenXXL}px)`}),aD=e=>{const t=e,n=[].concat(o2).reverse();return n.forEach((r,o)=>{const i=r.toUpperCase(),a=`screen${i}Min`,l=`screen${i}`;if(!(t[a]<=t[l]))throw new Error(`${a}<=${l} fails : !(${t[a]}<=${t[l]})`);if(o{const n=new Map;let r=-1,o={};return{matchHandlers:{},dispatch(i){return o=i,n.forEach(a=>a(o)),n.size>=1},subscribe(i){return n.size||this.register(),r+=1,n.set(r,i),i(o),r},unsubscribe(i){n.delete(i),n.size||this.unregister()},unregister(){Object.keys(t).forEach(i=>{const a=t[i],l=this.matchHandlers[a];l==null||l.mql.removeListener(l==null?void 0:l.listener)}),n.clear()},register(){Object.keys(t).forEach(i=>{const a=t[i],l=c=>{let{matches:u}=c;this.dispatch(Object.assign(Object.assign({},o),{[i]:u}))},s=window.matchMedia(a);s.addListener(l),this.matchHandlers[a]={mql:s,listener:l},l(s)})},responsiveMap:t}},[e])}function sD(){const[,e]=f.exports.useReducer(t=>t+1,0);return e}function cD(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!0;const t=f.exports.useRef({}),n=sD(),r=lD();return Nt(()=>{const o=r.subscribe(i=>{t.current=i,e&&n()});return()=>r.unsubscribe(o)},[]),t.current}const uD=f.exports.createContext({}),Cg=uD,dD=e=>{const{antCls:t,componentCls:n,iconCls:r,avatarBg:o,avatarColor:i,containerSize:a,containerSizeLG:l,containerSizeSM:s,textFontSize:c,textFontSizeLG:u,textFontSizeSM:d,borderRadius:v,borderRadiusLG:h,borderRadiusSM:g,lineWidth:p,lineType:b}=e,m=(y,S,x)=>({width:y,height:y,borderRadius:"50%",[`&${n}-square`]:{borderRadius:x},[`&${n}-icon`]:{fontSize:S,[`> ${r}`]:{margin:0}}});return{[n]:Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),{position:"relative",display:"inline-flex",justifyContent:"center",alignItems:"center",overflow:"hidden",color:i,whiteSpace:"nowrap",textAlign:"center",verticalAlign:"middle",background:o,border:`${X(p)} ${b} transparent`,["&-image"]:{background:"transparent"},[`${t}-image-img`]:{display:"block"}}),m(a,c,v)),{["&-lg"]:Object.assign({},m(l,u,h)),["&-sm"]:Object.assign({},m(s,d,g)),"> img":{display:"block",width:"100%",height:"100%",objectFit:"cover"}})}},fD=e=>{const{componentCls:t,groupBorderColor:n,groupOverlapping:r,groupSpace:o}=e;return{[`${t}-group`]:{display:"inline-flex",[`${t}`]:{borderColor:n},["> *:not(:first-child)"]:{marginInlineStart:r}},[`${t}-group-popover`]:{[`${t} + ${t}`]:{marginInlineStart:o}}}},vD=e=>{const{controlHeight:t,controlHeightLG:n,controlHeightSM:r,fontSize:o,fontSizeLG:i,fontSizeXL:a,fontSizeHeading3:l,marginXS:s,marginXXS:c,colorBorderBg:u}=e;return{containerSize:t,containerSizeLG:n,containerSizeSM:r,textFontSize:Math.round((i+a)/2),textFontSizeLG:l,textFontSizeSM:o,groupSpace:c,groupOverlapping:-s,groupBorderColor:u}},i2=vn("Avatar",e=>{const{colorTextLightSolid:t,colorTextPlaceholder:n}=e,r=$t(e,{avatarBg:n,avatarColor:t});return[dD(r),fD(r)]},vD);var pD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const[n,r]=f.exports.useState(1),[o,i]=f.exports.useState(!1),[a,l]=f.exports.useState(!0),s=f.exports.useRef(null),c=f.exports.useRef(null),u=xr(t,s),{getPrefixCls:d,avatar:v}=f.exports.useContext(ot),h=f.exports.useContext(Cg),g=()=>{if(!c.current||!s.current)return;const q=c.current.offsetWidth,ee=s.current.offsetWidth;if(q!==0&&ee!==0){const{gap:Z=4}=e;Z*2{i(!0)},[]),f.exports.useEffect(()=>{l(!0),r(1)},[e.src]),f.exports.useEffect(g,[e.gap]);const p=()=>{const{onError:q}=e;(q==null?void 0:q())!==!1&&l(!1)},{prefixCls:b,shape:m,size:y,src:S,srcSet:x,icon:$,className:E,rootClassName:w,alt:R,draggable:P,children:N,crossOrigin:I}=e,z=pD(e,["prefixCls","shape","size","src","srcSet","icon","className","rootClassName","alt","draggable","children","crossOrigin"]),F=So(q=>{var ee,Z;return(Z=(ee=y!=null?y:h==null?void 0:h.size)!==null&&ee!==void 0?ee:q)!==null&&Z!==void 0?Z:"default"}),T=Object.keys(typeof F=="object"?F||{}:{}).some(q=>["xs","sm","md","lg","xl","xxl"].includes(q)),D=cD(T),_=f.exports.useMemo(()=>{if(typeof F!="object")return{};const q=o2.find(Z=>D[Z]),ee=F[q];return ee?{width:ee,height:ee,fontSize:ee&&($||N)?ee/2:18}:{}},[D,F]),O=d("avatar",b),M=no(O),[L,A,B]=i2(O,M),k=te({[`${O}-lg`]:F==="large",[`${O}-sm`]:F==="small"}),j=f.exports.isValidElement(S),H=m||(h==null?void 0:h.shape)||"circle",W=te(O,k,v==null?void 0:v.className,`${O}-${H}`,{[`${O}-image`]:j||S&&a,[`${O}-icon`]:!!$},B,M,E,w,A),Y=typeof F=="number"?{width:F,height:F,fontSize:$?F/2:18}:{};let K;if(typeof S=="string"&&a)K=C("img",{src:S,draggable:P,srcSet:x,onError:p,alt:R,crossOrigin:I});else if(j)K=S;else if($)K=$;else if(o||n!==1){const q=`scale(${n})`,ee={msTransform:q,WebkitTransform:q,transform:q};K=C(mr,{onResize:g,children:C("span",{className:`${O}-string`,ref:c,style:Object.assign({},ee),children:N})})}else K=C("span",{className:`${O}-string`,style:{opacity:0},ref:c,children:N});return delete z.onError,delete z.gap,L(C("span",{...Object.assign({},z,{style:Object.assign(Object.assign(Object.assign(Object.assign({},Y),_),v==null?void 0:v.style),z.style),className:W,ref:u}),children:K}))},hD=f.exports.forwardRef(gD),a2=hD,td=e=>e?typeof e=="function"?e():e:null;function gm(e){var t=e.children,n=e.prefixCls,r=e.id,o=e.overlayInnerStyle,i=e.className,a=e.style;return C("div",{className:te("".concat(n,"-content"),i),style:a,children:C("div",{className:"".concat(n,"-inner"),id:r,role:"tooltip",style:o,children:typeof t=="function"?t():t})})}var Zi={shiftX:64,adjustY:1},Ji={adjustX:1,shiftY:!0},ur=[0,0],mD={left:{points:["cr","cl"],overflow:Ji,offset:[-4,0],targetOffset:ur},right:{points:["cl","cr"],overflow:Ji,offset:[4,0],targetOffset:ur},top:{points:["bc","tc"],overflow:Zi,offset:[0,-4],targetOffset:ur},bottom:{points:["tc","bc"],overflow:Zi,offset:[0,4],targetOffset:ur},topLeft:{points:["bl","tl"],overflow:Zi,offset:[0,-4],targetOffset:ur},leftTop:{points:["tr","tl"],overflow:Ji,offset:[-4,0],targetOffset:ur},topRight:{points:["br","tr"],overflow:Zi,offset:[0,-4],targetOffset:ur},rightTop:{points:["tl","tr"],overflow:Ji,offset:[4,0],targetOffset:ur},bottomRight:{points:["tr","br"],overflow:Zi,offset:[0,4],targetOffset:ur},rightBottom:{points:["bl","br"],overflow:Ji,offset:[4,0],targetOffset:ur},bottomLeft:{points:["tl","bl"],overflow:Zi,offset:[0,4],targetOffset:ur},leftBottom:{points:["br","bl"],overflow:Ji,offset:[-4,0],targetOffset:ur}},yD=["overlayClassName","trigger","mouseEnterDelay","mouseLeaveDelay","overlayStyle","prefixCls","children","onVisibleChange","afterVisibleChange","transitionName","animation","motion","placement","align","destroyTooltipOnHide","defaultVisible","getTooltipContainer","overlayInnerStyle","arrowContent","overlay","id","showArrow"],bD=function(t,n){var r=t.overlayClassName,o=t.trigger,i=o===void 0?["hover"]:o,a=t.mouseEnterDelay,l=a===void 0?0:a,s=t.mouseLeaveDelay,c=s===void 0?.1:s,u=t.overlayStyle,d=t.prefixCls,v=d===void 0?"rc-tooltip":d,h=t.children,g=t.onVisibleChange,p=t.afterVisibleChange,b=t.transitionName,m=t.animation,y=t.motion,S=t.placement,x=S===void 0?"right":S,$=t.align,E=$===void 0?{}:$,w=t.destroyTooltipOnHide,R=w===void 0?!1:w,P=t.defaultVisible,N=t.getTooltipContainer,I=t.overlayInnerStyle;t.arrowContent;var z=t.overlay,F=t.id,T=t.showArrow,D=T===void 0?!0:T,_=Je(t,yD),O=f.exports.useRef(null);f.exports.useImperativeHandle(n,function(){return O.current});var M=U({},_);"visible"in t&&(M.popupVisible=t.visible);var L=function(){return C(gm,{prefixCls:v,id:F,overlayInnerStyle:I,children:z},"content")};return C(lf,{popupClassName:r,prefixCls:v,popup:L,action:i,builtinPlacements:mD,popupPlacement:x,ref:O,popupAlign:E,getPopupContainer:N,onPopupVisibleChange:g,afterPopupVisibleChange:p,popupTransitionName:b,popupAnimation:m,popupMotion:y,defaultPopupVisible:P,autoDestroy:R,mouseLeaveDelay:c,popupStyle:u,mouseEnterDelay:l,arrow:D,...M,children:h})};const SD=f.exports.forwardRef(bD);function hm(e){const{sizePopupArrow:t,borderRadiusXS:n,borderRadiusOuter:r}=e,o=t/2,i=0,a=o,l=r*1/Math.sqrt(2),s=o-r*(1-1/Math.sqrt(2)),c=o-n*(1/Math.sqrt(2)),u=r*(Math.sqrt(2)-1)+n*(1/Math.sqrt(2)),d=2*o-c,v=u,h=2*o-l,g=s,p=2*o-i,b=a,m=o*Math.sqrt(2)+r*(Math.sqrt(2)-2),y=r*(Math.sqrt(2)-1),S=`polygon(${y}px 100%, 50% ${y}px, ${2*o-y}px 100%, ${y}px 100%)`,x=`path('M ${i} ${a} A ${r} ${r} 0 0 0 ${l} ${s} L ${c} ${u} A ${n} ${n} 0 0 1 ${d} ${v} L ${h} ${g} A ${r} ${r} 0 0 0 ${p} ${b} Z')`;return{arrowShadowWidth:m,arrowPath:x,arrowPolygon:S}}const l2=(e,t,n)=>{const{sizePopupArrow:r,arrowPolygon:o,arrowPath:i,arrowShadowWidth:a,borderRadiusXS:l,calc:s}=e;return{pointerEvents:"none",width:r,height:r,overflow:"hidden","&::before":{position:"absolute",bottom:0,insetInlineStart:0,width:r,height:s(r).div(2).equal(),background:t,clipPath:{_multi_value_:!0,value:[o,i]},content:'""'},"&::after":{content:'""',position:"absolute",width:a,height:a,bottom:0,insetInline:0,margin:"auto",borderRadius:{_skip_check_:!0,value:`0 0 ${X(l)} 0`},transform:"translateY(50%) rotate(-135deg)",boxShadow:n,zIndex:0,background:"transparent"}}},s2=8;function mm(e){const{contentRadius:t,limitVerticalRadius:n}=e,r=t>12?t+2:12;return{arrowOffsetHorizontal:r,arrowOffsetVertical:n?s2:r}}function _c(e,t){return e?t:{}}function c2(e,t,n){const{componentCls:r,boxShadowPopoverArrow:o,arrowOffsetVertical:i,arrowOffsetHorizontal:a}=e,{arrowDistance:l=0,arrowPlacement:s={left:!0,right:!0,top:!0,bottom:!0}}=n||{};return{[r]:Object.assign(Object.assign(Object.assign(Object.assign({[`${r}-arrow`]:[Object.assign(Object.assign({position:"absolute",zIndex:1,display:"block"},l2(e,t,o)),{"&:before":{background:t}})]},_c(!!s.top,{[[`&-placement-top > ${r}-arrow`,`&-placement-topLeft > ${r}-arrow`,`&-placement-topRight > ${r}-arrow`].join(",")]:{bottom:l,transform:"translateY(100%) rotate(180deg)"},[`&-placement-top > ${r}-arrow`]:{left:{_skip_check_:!0,value:"50%"},transform:"translateX(-50%) translateY(100%) rotate(180deg)"},[`&-placement-topLeft > ${r}-arrow`]:{left:{_skip_check_:!0,value:a}},[`&-placement-topRight > ${r}-arrow`]:{right:{_skip_check_:!0,value:a}}})),_c(!!s.bottom,{[[`&-placement-bottom > ${r}-arrow`,`&-placement-bottomLeft > ${r}-arrow`,`&-placement-bottomRight > ${r}-arrow`].join(",")]:{top:l,transform:"translateY(-100%)"},[`&-placement-bottom > ${r}-arrow`]:{left:{_skip_check_:!0,value:"50%"},transform:"translateX(-50%) translateY(-100%)"},[`&-placement-bottomLeft > ${r}-arrow`]:{left:{_skip_check_:!0,value:a}},[`&-placement-bottomRight > ${r}-arrow`]:{right:{_skip_check_:!0,value:a}}})),_c(!!s.left,{[[`&-placement-left > ${r}-arrow`,`&-placement-leftTop > ${r}-arrow`,`&-placement-leftBottom > ${r}-arrow`].join(",")]:{right:{_skip_check_:!0,value:l},transform:"translateX(100%) rotate(90deg)"},[`&-placement-left > ${r}-arrow`]:{top:{_skip_check_:!0,value:"50%"},transform:"translateY(-50%) translateX(100%) rotate(90deg)"},[`&-placement-leftTop > ${r}-arrow`]:{top:i},[`&-placement-leftBottom > ${r}-arrow`]:{bottom:i}})),_c(!!s.right,{[[`&-placement-right > ${r}-arrow`,`&-placement-rightTop > ${r}-arrow`,`&-placement-rightBottom > ${r}-arrow`].join(",")]:{left:{_skip_check_:!0,value:l},transform:"translateX(-100%) rotate(-90deg)"},[`&-placement-right > ${r}-arrow`]:{top:{_skip_check_:!0,value:"50%"},transform:"translateY(-50%) translateX(-100%) rotate(-90deg)"},[`&-placement-rightTop > ${r}-arrow`]:{top:i},[`&-placement-rightBottom > ${r}-arrow`]:{bottom:i}}))}}function CD(e,t,n,r){if(r===!1)return{adjustX:!1,adjustY:!1};const o=r&&typeof r=="object"?r:{},i={};switch(e){case"top":case"bottom":i.shiftX=t.arrowOffsetHorizontal*2+n,i.shiftY=!0,i.adjustY=!0;break;case"left":case"right":i.shiftY=t.arrowOffsetVertical*2+n,i.shiftX=!0,i.adjustX=!0;break}const a=Object.assign(Object.assign({},i),o);return a.shiftX||(a.adjustX=!0),a.shiftY||(a.adjustY=!0),a}const Db={left:{points:["cr","cl"]},right:{points:["cl","cr"]},top:{points:["bc","tc"]},bottom:{points:["tc","bc"]},topLeft:{points:["bl","tl"]},leftTop:{points:["tr","tl"]},topRight:{points:["br","tr"]},rightTop:{points:["tl","tr"]},bottomRight:{points:["tr","br"]},rightBottom:{points:["bl","br"]},bottomLeft:{points:["tl","bl"]},leftBottom:{points:["br","bl"]}},xD={topLeft:{points:["bl","tc"]},leftTop:{points:["tr","cl"]},topRight:{points:["br","tc"]},rightTop:{points:["tl","cr"]},bottomRight:{points:["tr","bc"]},rightBottom:{points:["bl","cr"]},bottomLeft:{points:["tl","bc"]},leftBottom:{points:["br","cl"]}},wD=new Set(["topLeft","topRight","bottomLeft","bottomRight","leftTop","leftBottom","rightTop","rightBottom"]);function $D(e){const{arrowWidth:t,autoAdjustOverflow:n,arrowPointAtCenter:r,offset:o,borderRadius:i,visibleFirst:a}=e,l=t/2,s={};return Object.keys(Db).forEach(c=>{const u=r&&xD[c]||Db[c],d=Object.assign(Object.assign({},u),{offset:[0,0],dynamicInset:!0});switch(s[c]=d,wD.has(c)&&(d.autoArrow=!1),c){case"top":case"topLeft":case"topRight":d.offset[1]=-l-o;break;case"bottom":case"bottomLeft":case"bottomRight":d.offset[1]=l+o;break;case"left":case"leftTop":case"leftBottom":d.offset[0]=-l-o;break;case"right":case"rightTop":case"rightBottom":d.offset[0]=l+o;break}const v=mm({contentRadius:i,limitVerticalRadius:!0});if(r)switch(c){case"topLeft":case"bottomLeft":d.offset[0]=-v.arrowOffsetHorizontal-l;break;case"topRight":case"bottomRight":d.offset[0]=v.arrowOffsetHorizontal+l;break;case"leftTop":case"rightTop":d.offset[1]=-v.arrowOffsetHorizontal-l;break;case"leftBottom":case"rightBottom":d.offset[1]=v.arrowOffsetHorizontal+l;break}d.overflow=CD(c,v,t,n),a&&(d.htmlRegion="visibleFirst")}),s}const ED=e=>{const{componentCls:t,tooltipMaxWidth:n,tooltipColor:r,tooltipBg:o,tooltipBorderRadius:i,zIndexPopup:a,controlHeight:l,boxShadowSecondary:s,paddingSM:c,paddingXS:u}=e;return[{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),{position:"absolute",zIndex:a,display:"block",width:"max-content",maxWidth:n,visibility:"visible",transformOrigin:"var(--arrow-x, 50%) var(--arrow-y, 50%)","&-hidden":{display:"none"},"--antd-arrow-background-color":o,[`${t}-inner`]:{minWidth:l,minHeight:l,padding:`${X(e.calc(c).div(2).equal())} ${X(u)}`,color:r,textAlign:"start",textDecoration:"none",wordWrap:"break-word",backgroundColor:o,borderRadius:i,boxShadow:s,boxSizing:"border-box"},[["&-placement-left","&-placement-leftTop","&-placement-leftBottom","&-placement-right","&-placement-rightTop","&-placement-rightBottom"].join(",")]:{[`${t}-inner`]:{borderRadius:e.min(i,s2)}},[`${t}-content`]:{position:"relative"}}),ow(e,(d,v)=>{let{darkColor:h}=v;return{[`&${t}-${d}`]:{[`${t}-inner`]:{backgroundColor:h},[`${t}-arrow`]:{"--antd-arrow-background-color":h}}}})),{"&-rtl":{direction:"rtl"}})},c2(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow}}]},MD=e=>Object.assign(Object.assign({zIndexPopup:e.zIndexPopupBase+70},mm({contentRadius:e.borderRadius,limitVerticalRadius:!0})),hm($t(e,{borderRadiusOuter:Math.min(e.borderRadiusOuter,4)}))),u2=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return vn("Tooltip",r=>{const{borderRadius:o,colorTextLightSolid:i,colorBgSpotlight:a}=r,l=$t(r,{tooltipMaxWidth:250,tooltipColor:i,tooltipBorderRadius:o,tooltipBg:a});return[ED(l),of(r,"zoom-big-fast")]},MD,{resetStyle:!1,injectStyle:t})(e)},OD=$s.map(e=>`${e}-inverse`),RD=["success","processing","error","default","warning"];function d2(e){return(arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0)?[].concat(Oe(OD),Oe($s)).includes(e):$s.includes(e)}function ID(e){return RD.includes(e)}function f2(e,t){const n=d2(t),r=te({[`${e}-${t}`]:t&&n}),o={},i={};return t&&!n&&(o.background=t,i["--antd-arrow-background-color"]=t),{className:r,overlayStyle:o,arrowStyle:i}}const PD=e=>{const{prefixCls:t,className:n,placement:r="top",title:o,color:i,overlayInnerStyle:a}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("tooltip",t),[c,u,d]=u2(s),v=f2(s,i),h=v.arrowStyle,g=Object.assign(Object.assign({},a),v.overlayStyle),p=te(u,d,s,`${s}-pure`,`${s}-placement-${r}`,n,v.className);return c(ie("div",{className:p,style:h,children:[C("div",{className:`${s}-arrow`}),C(gm,{...Object.assign({},e,{className:u,prefixCls:s,overlayInnerStyle:g}),children:o})]}))},TD=PD;var ND=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n,r;const{prefixCls:o,openClassName:i,getTooltipContainer:a,overlayClassName:l,color:s,overlayInnerStyle:c,children:u,afterOpenChange:d,afterVisibleChange:v,destroyTooltipOnHide:h,arrow:g=!0,title:p,overlay:b,builtinPlacements:m,arrowPointAtCenter:y=!1,autoAdjustOverflow:S=!0}=e,x=!!g,[,$]=Kn(),{getPopupContainer:E,getPrefixCls:w,direction:R}=f.exports.useContext(ot),P=jx(),N=f.exports.useRef(null),I=()=>{var ce;(ce=N.current)===null||ce===void 0||ce.forceAlign()};f.exports.useImperativeHandle(t,()=>({forceAlign:I,forcePopupAlign:()=>{P.deprecated(!1,"forcePopupAlign","forceAlign"),I()}}));const[z,F]=kt(!1,{value:(n=e.open)!==null&&n!==void 0?n:e.visible,defaultValue:(r=e.defaultOpen)!==null&&r!==void 0?r:e.defaultVisible}),T=!p&&!b&&p!==0,D=ce=>{var de,xe;F(T?!1:ce),T||((de=e.onOpenChange)===null||de===void 0||de.call(e,ce),(xe=e.onVisibleChange)===null||xe===void 0||xe.call(e,ce))},_=f.exports.useMemo(()=>{var ce,de;let xe=y;return typeof g=="object"&&(xe=(de=(ce=g.pointAtCenter)!==null&&ce!==void 0?ce:g.arrowPointAtCenter)!==null&&de!==void 0?de:y),m||$D({arrowPointAtCenter:xe,autoAdjustOverflow:S,arrowWidth:x?$.sizePopupArrow:0,borderRadius:$.borderRadius,offset:$.marginXXS,visibleFirst:!0})},[y,g,m,$]),O=f.exports.useMemo(()=>p===0?p:b||p||"",[b,p]),M=C(ig,{children:typeof O=="function"?O():O}),{getPopupContainer:L,placement:A="top",mouseEnterDelay:B=.1,mouseLeaveDelay:k=.1,overlayStyle:j,rootClassName:H}=e,W=ND(e,["getPopupContainer","placement","mouseEnterDelay","mouseLeaveDelay","overlayStyle","rootClassName"]),Y=w("tooltip",o),K=w(),q=e["data-popover-inject"];let ee=z;!("open"in e)&&!("visible"in e)&&T&&(ee=!1);const Z=Es(u)&&!hw(u)?u:C("span",{children:u}),Q=Z.props,ne=!Q.className||typeof Q.className=="string"?te(Q.className,i||`${Y}-open`):Q.className,[ae,J,re]=u2(Y,!q),fe=f2(Y,s),ve=fe.arrowStyle,pe=Object.assign(Object.assign({},c),fe.overlayStyle),oe=te(l,{[`${Y}-rtl`]:R==="rtl"},fe.className,H,J,re),[se,le]=Qd("Tooltip",W.zIndex),Ce=C(SD,{...Object.assign({},W,{zIndex:se,showArrow:x,placement:A,mouseEnterDelay:B,mouseLeaveDelay:k,prefixCls:Y,overlayClassName:oe,overlayStyle:Object.assign(Object.assign({},ve),j),getTooltipContainer:L||a||E,ref:N,builtinPlacements:_,overlay:M,visible:ee,onVisibleChange:D,afterVisibleChange:d!=null?d:v,overlayInnerStyle:pe,arrowContent:C("span",{className:`${Y}-arrow-content`}),motion:{motionName:ni(K,"zoom-big-fast",e.transitionName),motionDeadline:1e3},destroyTooltipOnHide:!!h}),children:ee?ti(Z,{className:ne}):Z});return ae(f.exports.createElement(mw.Provider,{value:le},Ce))});v2._InternalPanelDoNotUseOrYouWillBeFired=TD;const p2=v2,_D=e=>{const{componentCls:t,popoverColor:n,titleMinWidth:r,fontWeightStrong:o,innerPadding:i,boxShadowSecondary:a,colorTextHeading:l,borderRadiusLG:s,zIndexPopup:c,titleMarginBottom:u,colorBgElevated:d,popoverBg:v,titleBorderBottom:h,innerContentPadding:g,titlePadding:p}=e;return[{[t]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",top:0,left:{_skip_check_:!0,value:0},zIndex:c,fontWeight:"normal",whiteSpace:"normal",textAlign:"start",cursor:"auto",userSelect:"text",transformOrigin:"var(--arrow-x, 50%) var(--arrow-y, 50%)","--antd-arrow-background-color":d,"&-rtl":{direction:"rtl"},"&-hidden":{display:"none"},[`${t}-content`]:{position:"relative"},[`${t}-inner`]:{backgroundColor:v,backgroundClip:"padding-box",borderRadius:s,boxShadow:a,padding:i},[`${t}-title`]:{minWidth:r,marginBottom:u,color:l,fontWeight:o,borderBottom:h,padding:p},[`${t}-inner-content`]:{color:n,padding:g}})},c2(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow,display:"inline-block",[`${t}-content`]:{display:"inline-block"}}}]},AD=e=>{const{componentCls:t}=e;return{[t]:$s.map(n=>{const r=e[`${n}6`];return{[`&${t}-${n}`]:{"--antd-arrow-background-color":r,[`${t}-inner`]:{backgroundColor:r},[`${t}-arrow`]:{background:"transparent"}}}})}},DD=e=>{const{lineWidth:t,controlHeight:n,fontHeight:r,padding:o,wireframe:i,zIndexPopupBase:a,borderRadiusLG:l,marginXS:s,lineType:c,colorSplit:u,paddingSM:d}=e,v=n-r,h=v/2,g=v/2-t,p=o;return Object.assign(Object.assign(Object.assign({titleMinWidth:177,zIndexPopup:a+30},hm(e)),mm({contentRadius:l,limitVerticalRadius:!0})),{innerPadding:i?0:12,titleMarginBottom:i?0:s,titlePadding:i?`${h}px ${p}px ${g}px`:0,titleBorderBottom:i?`${t}px ${c} ${u}`:"none",innerContentPadding:i?`${d}px ${p}px`:0})},g2=vn("Popover",e=>{const{colorBgElevated:t,colorText:n}=e,r=$t(e,{popoverBg:t,popoverColor:n});return[_D(r),AD(r),of(r,"zoom-big")]},DD,{resetStyle:!1,deprecatedTokens:[["width","titleMinWidth"],["minWidth","titleMinWidth"]]});var LD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o!t&&!n?null:ie(Tt,{children:[t&&C("div",{className:`${e}-title`,children:td(t)}),C("div",{className:`${e}-inner-content`,children:td(n)})]}),FD=e=>{const{hashId:t,prefixCls:n,className:r,style:o,placement:i="top",title:a,content:l,children:s}=e;return ie("div",{className:te(t,n,`${n}-pure`,`${n}-placement-${i}`,r),style:o,children:[C("div",{className:`${n}-arrow`}),C(gm,{...Object.assign({},e,{className:t,prefixCls:n}),children:s||zD(n,a,l)})]})},kD=e=>{const{prefixCls:t,className:n}=e,r=LD(e,["prefixCls","className"]),{getPrefixCls:o}=f.exports.useContext(ot),i=o("popover",t),[a,l,s]=g2(i);return a(C(FD,{...Object.assign({},r,{prefixCls:i,hashId:l,className:te(n,s)})}))},BD=kD;var jD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{let{title:t,content:n,prefixCls:r}=e;return ie(Tt,{children:[t&&C("div",{className:`${r}-title`,children:td(t)}),C("div",{className:`${r}-inner-content`,children:td(n)})]})},h2=f.exports.forwardRef((e,t)=>{const{prefixCls:n,title:r,content:o,overlayClassName:i,placement:a="top",trigger:l="hover",mouseEnterDelay:s=.1,mouseLeaveDelay:c=.1,overlayStyle:u={}}=e,d=jD(e,["prefixCls","title","content","overlayClassName","placement","trigger","mouseEnterDelay","mouseLeaveDelay","overlayStyle"]),{getPrefixCls:v}=f.exports.useContext(ot),h=v("popover",n),[g,p,b]=g2(h),m=v(),y=te(i,p,b);return g(C(p2,{...Object.assign({placement:a,trigger:l,mouseEnterDelay:s,mouseLeaveDelay:c,overlayStyle:u},d,{prefixCls:h,overlayClassName:y,ref:t,overlay:r||o?C(HD,{prefixCls:h,title:r,content:o}):null,transitionName:ni(m,"zoom-big",d.transitionName),"data-popover-inject":!0})}))});h2._InternalPanelDoNotUseOrYouWillBeFired=BD;const WD=h2,Lb=e=>{const{size:t,shape:n}=f.exports.useContext(Cg),r=f.exports.useMemo(()=>({size:e.size||t,shape:e.shape||n}),[e.size,e.shape,t,n]);return C(Cg.Provider,{value:r,children:e.children})},VD=e=>{const{getPrefixCls:t,direction:n}=f.exports.useContext(ot),{prefixCls:r,className:o,rootClassName:i,style:a,maxCount:l,maxStyle:s,size:c,shape:u,maxPopoverPlacement:d="top",maxPopoverTrigger:v="hover",children:h}=e,g=t("avatar",r),p=`${g}-group`,b=no(g),[m,y,S]=i2(g,b),x=te(p,{[`${p}-rtl`]:n==="rtl"},S,b,o,i,y),$=Qo(h).map((w,R)=>ti(w,{key:`avatar-key-${R}`})),E=$.length;if(l&&l1&&arguments[1]!==void 0?arguments[1]:!1;if(Jd(e)){var n=e.nodeName.toLowerCase(),r=["input","select","textarea","button"].includes(n)||e.isContentEditable||n==="a"&&!!e.getAttribute("href"),o=e.getAttribute("tabindex"),i=Number(o),a=null;return o&&!Number.isNaN(i)?a=i:r&&a===null&&(a=0),r&&e.disabled&&(a=null),a!==null&&(a>=0||t&&a<0)}return!1}function rL(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=Oe(e.querySelectorAll("*")).filter(function(r){return zb(r,t)});return zb(e,t)&&n.unshift(e),n}var xg=ue.LEFT,wg=ue.RIGHT,$g=ue.UP,au=ue.DOWN,lu=ue.ENTER,$2=ue.ESC,$l=ue.HOME,El=ue.END,Fb=[$g,au,xg,wg];function oL(e,t,n,r){var o,i,a,l,s="prev",c="next",u="children",d="parent";if(e==="inline"&&r===lu)return{inlineTrigger:!0};var v=(o={},V(o,$g,s),V(o,au,c),o),h=(i={},V(i,xg,n?c:s),V(i,wg,n?s:c),V(i,au,u),V(i,lu,u),i),g=(a={},V(a,$g,s),V(a,au,c),V(a,lu,u),V(a,$2,d),V(a,xg,n?u:d),V(a,wg,n?d:u),a),p={inline:v,horizontal:h,vertical:g,inlineSub:v,horizontalSub:g,verticalSub:g},b=(l=p["".concat(e).concat(t?"":"Sub")])===null||l===void 0?void 0:l[r];switch(b){case s:return{offset:-1,sibling:!0};case c:return{offset:1,sibling:!0};case d:return{offset:-1,sibling:!1};case u:return{offset:1,sibling:!1};default:return null}}function iL(e){for(var t=e;t;){if(t.getAttribute("data-menu-list"))return t;t=t.parentElement}return null}function aL(e,t){for(var n=e||document.activeElement;n;){if(t.has(n))return n;n=n.parentElement}return null}function bm(e,t){var n=rL(e,!0);return n.filter(function(r){return t.has(r)})}function kb(e,t,n){var r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:1;if(!e)return null;var o=bm(e,t),i=o.length,a=o.findIndex(function(l){return n===l});return r<0?a===-1?a=i-1:a-=1:r>0&&(a+=1),a=(a+i)%i,o[a]}var Eg=function(t,n){var r=new Set,o=new Map,i=new Map;return t.forEach(function(a){var l=document.querySelector("[data-menu-id='".concat(b2(n,a),"']"));l&&(r.add(l),i.set(l,a),o.set(a,l))}),{elements:r,key2element:o,element2key:i}};function lL(e,t,n,r,o,i,a,l,s,c){var u=f.exports.useRef(),d=f.exports.useRef();d.current=t;var v=function(){St.cancel(u.current)};return f.exports.useEffect(function(){return function(){v()}},[]),function(h){var g=h.which;if([].concat(Fb,[lu,$2,$l,El]).includes(g)){var p=i(),b=Eg(p,r),m=b,y=m.elements,S=m.key2element,x=m.element2key,$=S.get(t),E=aL($,y),w=x.get(E),R=oL(e,a(w,!0).length===1,n,g);if(!R&&g!==$l&&g!==El)return;(Fb.includes(g)||[$l,El].includes(g))&&h.preventDefault();var P=function(O){if(O){var M=O,L=O.querySelector("a");L!=null&&L.getAttribute("href")&&(M=L);var A=x.get(O);l(A),v(),u.current=St(function(){d.current===A&&M.focus()})}};if([$l,El].includes(g)||R.sibling||!E){var N;!E||e==="inline"?N=o.current:N=iL(E);var I,z=bm(N,y);g===$l?I=z[0]:g===El?I=z[z.length-1]:I=kb(N,y,E,R.offset),P(I)}else if(R.inlineTrigger)s(w);else if(R.offset>0)s(w,!0),v(),u.current=St(function(){b=Eg(p,r);var _=E.getAttribute("aria-controls"),O=document.getElementById(_),M=kb(O,b.elements);P(M)},5);else if(R.offset<0){var F=a(w,!0),T=F[F.length-2],D=S.get(T);s(T,!1),P(D)}}c==null||c(h)}}function sL(e){Promise.resolve().then(e)}var Sm="__RC_UTIL_PATH_SPLIT__",Bb=function(t){return t.join(Sm)},cL=function(t){return t.split(Sm)},Mg="rc-menu-more";function uL(){var e=f.exports.useState({}),t=G(e,2),n=t[1],r=f.exports.useRef(new Map),o=f.exports.useRef(new Map),i=f.exports.useState([]),a=G(i,2),l=a[0],s=a[1],c=f.exports.useRef(0),u=f.exports.useRef(!1),d=function(){u.current||n({})},v=f.exports.useCallback(function(S,x){var $=Bb(x);o.current.set($,S),r.current.set(S,$),c.current+=1;var E=c.current;sL(function(){E===c.current&&d()})},[]),h=f.exports.useCallback(function(S,x){var $=Bb(x);o.current.delete($),r.current.delete(S)},[]),g=f.exports.useCallback(function(S){s(S)},[]),p=f.exports.useCallback(function(S,x){var $=r.current.get(S)||"",E=cL($);return x&&l.includes(E[0])&&E.unshift(Mg),E},[l]),b=f.exports.useCallback(function(S,x){return S.some(function($){var E=p($,!0);return E.includes(x)})},[p]),m=function(){var x=Oe(r.current.keys());return l.length&&x.push(Mg),x},y=f.exports.useCallback(function(S){var x="".concat(r.current.get(S)).concat(Sm),$=new Set;return Oe(o.current.keys()).forEach(function(E){E.startsWith(x)&&$.add(o.current.get(E))}),$},[]);return f.exports.useEffect(function(){return function(){u.current=!0}},[]),{registerPath:v,unregisterPath:h,refreshOverflowKeys:g,isSubPathKey:b,getKeyPath:p,getKeys:m,getSubPathKeys:y}}function _l(e){var t=f.exports.useRef(e);t.current=e;var n=f.exports.useCallback(function(){for(var r,o=arguments.length,i=new Array(o),a=0;a1&&(y.motionAppear=!1);var S=y.onVisibleChanged;return y.onVisibleChanged=function(x){return!v.current&&!x&&b(!0),S==null?void 0:S(x)},p?null:C(Is,{mode:i,locked:!v.current,children:C(to,{visible:m,...y,forceRender:s,removeOnLeave:!1,leavedClassName:"".concat(l,"-hidden"),children:function(x){var $=x.className,E=x.style;return C(Cm,{id:t,className:$,style:E,children:o})}})})}var OL=["style","className","title","eventKey","warnKey","disabled","internalPopupClose","children","itemIcon","expandIcon","popupClassName","popupOffset","popupStyle","onClick","onMouseEnter","onMouseLeave","onTitleClick","onTitleMouseEnter","onTitleMouseLeave"],RL=["active"],IL=function(t){var n,r=t.style,o=t.className,i=t.title,a=t.eventKey;t.warnKey;var l=t.disabled,s=t.internalPopupClose,c=t.children,u=t.itemIcon,d=t.expandIcon,v=t.popupClassName,h=t.popupOffset,g=t.popupStyle,p=t.onClick,b=t.onMouseEnter,m=t.onMouseLeave,y=t.onTitleClick,S=t.onTitleMouseEnter,x=t.onTitleMouseLeave,$=Je(t,OL),E=S2(a),w=f.exports.useContext(jr),R=w.prefixCls,P=w.mode,N=w.openKeys,I=w.disabled,z=w.overflowDisabled,F=w.activeKey,T=w.selectedKeys,D=w.itemIcon,_=w.expandIcon,O=w.onItemClick,M=w.onOpenChange,L=w.onActive,A=f.exports.useContext(ym),B=A._internalRenderSubMenuItem,k=f.exports.useContext(w2),j=k.isSubPathKey,H=Xs(),W="".concat(R,"-submenu"),Y=I||l,K=f.exports.useRef(),q=f.exports.useRef(),ee=u!=null?u:D,Z=d!=null?d:_,Q=N.includes(a),ne=!z&&Q,ae=j(T,a),J=E2(a,Y,S,x),re=J.active,fe=Je(J,RL),ve=f.exports.useState(!1),pe=G(ve,2),oe=pe[0],se=pe[1],le=function(_e){Y||se(_e)},Ce=function(_e){le(!0),b==null||b({key:a,domEvent:_e})},ce=function(_e){le(!1),m==null||m({key:a,domEvent:_e})},de=f.exports.useMemo(function(){return re||(P!=="inline"?oe||j([F],a):!1)},[P,re,F,oe,a,j]),xe=M2(H.length),he=function(_e){Y||(y==null||y({key:a,domEvent:_e}),P==="inline"&&M(a,!Q))},ke=_l(function(Ee){p==null||p(nd(Ee)),O(Ee)}),we=function(_e){P!=="inline"&&M(a,_e)},ge=function(){L(a)},Pe=E&&"".concat(E,"-popup"),Se=ie("div",{role:"menuitem",style:xe,className:"".concat(W,"-title"),tabIndex:Y?null:-1,ref:K,title:typeof i=="string"?i:null,"data-menu-id":z&&E?null:E,"aria-expanded":ne,"aria-haspopup":!0,"aria-controls":Pe,"aria-disabled":Y,onClick:he,onFocus:ge,...fe,children:[i,C(O2,{icon:P!=="horizontal"?Z:void 0,props:U(U({},t),{},{isOpen:ne,isSubMenu:!0}),children:C("i",{className:"".concat(W,"-arrow")})})]}),st=f.exports.useRef(P);if(P!=="inline"&&H.length>1?st.current="vertical":st.current=P,!z){var nt=st.current;Se=C(EL,{mode:nt,prefixCls:W,visible:!s&&ne&&P!=="inline",popupClassName:v,popupOffset:h,popupStyle:g,popup:C(Is,{mode:nt==="horizontal"?"vertical":nt,children:C(Cm,{id:Pe,ref:q,children:c})}),disabled:Y,onVisibleChange:we,children:Se})}var Ne=ie(Zr.Item,{role:"none",...$,component:"li",style:r,className:te(W,"".concat(W,"-").concat(P),o,(n={},V(n,"".concat(W,"-open"),ne),V(n,"".concat(W,"-active"),de),V(n,"".concat(W,"-selected"),ae),V(n,"".concat(W,"-disabled"),Y),n)),onMouseEnter:Ce,onMouseLeave:ce,children:[Se,!z&&C(ML,{id:Pe,open:ne,keyPath:H,children:c})]});return B&&(Ne=B(Ne,t,{selected:ae,active:de,open:ne,disabled:Y})),C(Is,{onItemClick:ke,mode:P==="horizontal"?"vertical":P,itemIcon:ee,expandIcon:Z,children:Ne})};function wm(e){var t=e.eventKey,n=e.children,r=Xs(t),o=xm(n,r),i=sf();f.exports.useEffect(function(){if(i)return i.registerPath(t,r),function(){i.unregisterPath(t,r)}},[r]);var a;return i?a=o:a=C(IL,{...e,children:o}),C(x2.Provider,{value:r,children:a})}var PL=["className","title","eventKey","children"],TL=["children"],NL=function(t){var n=t.className,r=t.title;t.eventKey;var o=t.children,i=Je(t,PL),a=f.exports.useContext(jr),l=a.prefixCls,s="".concat(l,"-item-group");return ie("li",{role:"presentation",...i,onClick:function(u){return u.stopPropagation()},className:te(s,n),children:[C("div",{role:"presentation",className:"".concat(s,"-title"),title:typeof r=="string"?r:void 0,children:r}),C("ul",{role:"group",className:"".concat(s,"-list"),children:o})]})};function I2(e){var t=e.children,n=Je(e,TL),r=Xs(n.eventKey),o=xm(t,r),i=sf();return i?o:C(NL,{...lr(n,["warnKey"]),children:o})}function P2(e){var t=e.className,n=e.style,r=f.exports.useContext(jr),o=r.prefixCls,i=sf();return i?null:C("li",{role:"separator",className:te("".concat(o,"-item-divider"),t),style:n})}var _L=["label","children","key","type"];function Og(e){return(e||[]).map(function(t,n){if(t&&Qe(t)==="object"){var r=t,o=r.label,i=r.children,a=r.key,l=r.type,s=Je(r,_L),c=a!=null?a:"tmp-".concat(n);return i||l==="group"?l==="group"?C(I2,{...s,title:o,children:Og(i)},c):C(wm,{...s,title:o,children:Og(i)},c):l==="divider"?C(P2,{...s},c):C(cf,{...s,children:o},c)}return null}).filter(function(t){return t})}function AL(e,t,n){var r=e;return t&&(r=Og(t)),xm(r,n)}var DL=["prefixCls","rootClassName","style","className","tabIndex","items","children","direction","id","mode","inlineCollapsed","disabled","disabledOverflow","subMenuOpenDelay","subMenuCloseDelay","forceSubMenuRender","defaultOpenKeys","openKeys","activeKey","defaultActiveFirst","selectable","multiple","defaultSelectedKeys","selectedKeys","onSelect","onDeselect","inlineIndent","motion","defaultMotions","triggerSubMenuAction","builtinPlacements","itemIcon","expandIcon","overflowedIndicator","overflowedIndicatorPopupClassName","getPopupContainer","onClick","onOpenChange","onKeyDown","openAnimation","openTransitionName","_internalRenderMenuItem","_internalRenderSubMenuItem"],na=[],LL=f.exports.forwardRef(function(e,t){var n,r,o=e,i=o.prefixCls,a=i===void 0?"rc-menu":i,l=o.rootClassName,s=o.style,c=o.className,u=o.tabIndex,d=u===void 0?0:u,v=o.items,h=o.children,g=o.direction,p=o.id,b=o.mode,m=b===void 0?"vertical":b,y=o.inlineCollapsed,S=o.disabled,x=o.disabledOverflow,$=o.subMenuOpenDelay,E=$===void 0?.1:$,w=o.subMenuCloseDelay,R=w===void 0?.1:w,P=o.forceSubMenuRender,N=o.defaultOpenKeys,I=o.openKeys,z=o.activeKey,F=o.defaultActiveFirst,T=o.selectable,D=T===void 0?!0:T,_=o.multiple,O=_===void 0?!1:_,M=o.defaultSelectedKeys,L=o.selectedKeys,A=o.onSelect,B=o.onDeselect,k=o.inlineIndent,j=k===void 0?24:k,H=o.motion,W=o.defaultMotions,Y=o.triggerSubMenuAction,K=Y===void 0?"hover":Y,q=o.builtinPlacements,ee=o.itemIcon,Z=o.expandIcon,Q=o.overflowedIndicator,ne=Q===void 0?"...":Q,ae=o.overflowedIndicatorPopupClassName,J=o.getPopupContainer,re=o.onClick,fe=o.onOpenChange,ve=o.onKeyDown;o.openAnimation,o.openTransitionName;var pe=o._internalRenderMenuItem,oe=o._internalRenderSubMenuItem,se=Je(o,DL),le=f.exports.useMemo(function(){return AL(h,v,na)},[h,v]),Ce=f.exports.useState(!1),ce=G(Ce,2),de=ce[0],xe=ce[1],he=f.exports.useRef(),ke=fL(p),we=g==="rtl",ge=kt(N,{value:I,postState:function(dt){return dt||na}}),Pe=G(ge,2),Se=Pe[0],st=Pe[1],nt=function(dt){var Fe=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;function Ye(){st(dt),fe==null||fe(dt)}Fe?Gn.exports.flushSync(Ye):Ye()},Ne=f.exports.useState(Se),Ee=G(Ne,2),_e=Ee[0],Be=Ee[1],qe=f.exports.useRef(!1),it=f.exports.useMemo(function(){return(m==="inline"||m==="vertical")&&y?["vertical",y]:[m,!1]},[m,y]),ft=G(it,2),ut=ft[0],Ue=ft[1],He=ut==="inline",Xe=f.exports.useState(ut),Le=G(Xe,2),Re=Le[0],be=Le[1],Ae=f.exports.useState(Ue),Me=G(Ae,2),$e=Me[0],Te=Me[1];f.exports.useEffect(function(){be(ut),Te(Ue),qe.current&&(He?st(_e):nt(na))},[ut,Ue]);var ye=f.exports.useState(0),Ge=G(ye,2),Ze=Ge[0],et=Ge[1],ht=Ze>=le.length-1||Re!=="horizontal"||x;f.exports.useEffect(function(){He&&Be(Se)},[Se]),f.exports.useEffect(function(){return qe.current=!0,function(){qe.current=!1}},[]);var mt=uL(),ct=mt.registerPath,We=mt.unregisterPath,Ve=mt.refreshOverflowKeys,vt=mt.isSubPathKey,Ie=mt.getKeyPath,ze=mt.getKeys,Ke=mt.getSubPathKeys,at=f.exports.useMemo(function(){return{registerPath:ct,unregisterPath:We}},[ct,We]),Gt=f.exports.useMemo(function(){return{isSubPathKey:vt}},[vt]);f.exports.useEffect(function(){Ve(ht?na:le.slice(Ze+1).map(function(bt){return bt.key}))},[Ze,ht]);var At=kt(z||F&&((n=le[0])===null||n===void 0?void 0:n.key),{value:z}),Zt=G(At,2),Jt=Zt[0],kn=Zt[1],qn=_l(function(bt){kn(bt)}),pn=_l(function(){kn(void 0)});f.exports.useImperativeHandle(t,function(){return{list:he.current,focus:function(dt){var Fe,Ye=ze(),yt=Eg(Ye,ke),Bt=yt.elements,It=yt.key2element,Kt=yt.element2key,sn=bm(he.current,Bt),Pn=Jt!=null?Jt:sn[0]?Kt.get(sn[0]):(Fe=le.find(function(jn){return!jn.props.disabled}))===null||Fe===void 0?void 0:Fe.key,cn=It.get(Pn);if(Pn&&cn){var Tn;cn==null||(Tn=cn.focus)===null||Tn===void 0||Tn.call(cn,dt)}}}});var Co=kt(M||[],{value:L,postState:function(dt){return Array.isArray(dt)?dt:dt==null?na:[dt]}}),xo=G(Co,2),In=xo[0],wo=xo[1],wr=function(dt){if(D){var Fe=dt.key,Ye=In.includes(Fe),yt;O?Ye?yt=In.filter(function(It){return It!==Fe}):yt=[].concat(Oe(In),[Fe]):yt=[Fe],wo(yt);var Bt=U(U({},dt),{},{selectedKeys:yt});Ye?B==null||B(Bt):A==null||A(Bt)}!O&&Se.length&&Re!=="inline"&&nt(na)},Bn=_l(function(bt){re==null||re(nd(bt)),wr(bt)}),sr=_l(function(bt,dt){var Fe=Se.filter(function(yt){return yt!==bt});if(dt)Fe.push(bt);else if(Re!=="inline"){var Ye=Ke(bt);Fe=Fe.filter(function(yt){return!Ye.has(yt)})}Vs(Se,Fe,!0)||nt(Fe,!0)}),$r=function(dt,Fe){var Ye=Fe!=null?Fe:!Se.includes(dt);sr(dt,Ye)},Ur=lL(Re,Jt,we,ke,he,ze,Ie,kn,$r,ve);f.exports.useEffect(function(){xe(!0)},[]);var Xn=f.exports.useMemo(function(){return{_internalRenderMenuItem:pe,_internalRenderSubMenuItem:oe}},[pe,oe]),$o=Re!=="horizontal"||x?le:le.map(function(bt,dt){return C(Is,{overflowDisabled:dt>Ze,children:bt},bt.key)}),Er=C(Zr,{id:p,ref:he,prefixCls:"".concat(a,"-overflow"),component:"ul",itemComponent:cf,className:te(a,"".concat(a,"-root"),"".concat(a,"-").concat(Re),c,(r={},V(r,"".concat(a,"-inline-collapsed"),$e),V(r,"".concat(a,"-rtl"),we),r),l),dir:g,style:s,role:"menu",tabIndex:d,data:$o,renderRawItem:function(dt){return dt},renderRawRest:function(dt){var Fe=dt.length,Ye=Fe?le.slice(-Fe):null;return C(wm,{eventKey:Mg,title:ne,disabled:ht,internalPopupClose:Fe===0,popupClassName:ae,children:Ye})},maxCount:Re!=="horizontal"||x?Zr.INVALIDATE:Zr.RESPONSIVE,ssr:"full","data-menu-list":!0,onVisibleChange:function(dt){et(dt)},onKeyDown:Ur,...se});return C(ym.Provider,{value:Xn,children:C(y2.Provider,{value:ke,children:ie(Is,{prefixCls:a,rootClassName:l,mode:Re,openKeys:Se,rtl:we,disabled:S,motion:de?H:null,defaultMotions:de?W:null,activeKey:Jt,onActive:qn,onInactive:pn,selectedKeys:In,inlineIndent:j,subMenuOpenDelay:E,subMenuCloseDelay:R,forceSubMenuRender:P,builtinPlacements:q,triggerSubMenuAction:K,getPopupContainer:J,itemIcon:ee,expandIcon:Z,onItemClick:Bn,onOpenChange:sr,children:[C(w2.Provider,{value:Gt,children:Er}),C("div",{style:{display:"none"},"aria-hidden":!0,children:C(C2.Provider,{value:at,children:le})})]})})})}),Qs=LL;Qs.Item=cf;Qs.SubMenu=wm;Qs.ItemGroup=I2;Qs.Divider=P2;var $m={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n=1e3,r=6e4,o=36e5,i="millisecond",a="second",l="minute",s="hour",c="day",u="week",d="month",v="quarter",h="year",g="date",p="Invalid Date",b=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,m=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,y={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(T){var D=["th","st","nd","rd"],_=T%100;return"["+T+(D[(_-20)%10]||D[_]||D[0])+"]"}},S=function(T,D,_){var O=String(T);return!O||O.length>=D?T:""+Array(D+1-O.length).join(_)+T},x={s:S,z:function(T){var D=-T.utcOffset(),_=Math.abs(D),O=Math.floor(_/60),M=_%60;return(D<=0?"+":"-")+S(O,2,"0")+":"+S(M,2,"0")},m:function T(D,_){if(D.date()<_.date())return-T(_,D);var O=12*(_.year()-D.year())+(_.month()-D.month()),M=D.clone().add(O,d),L=_-M<0,A=D.clone().add(O+(L?-1:1),d);return+(-(O+(_-M)/(L?M-A:A-M))||0)},a:function(T){return T<0?Math.ceil(T)||0:Math.floor(T)},p:function(T){return{M:d,y:h,w:u,d:c,D:g,h:s,m:l,s:a,ms:i,Q:v}[T]||String(T||"").toLowerCase().replace(/s$/,"")},u:function(T){return T===void 0}},$="en",E={};E[$]=y;var w="$isDayjsObject",R=function(T){return T instanceof z||!(!T||!T[w])},P=function T(D,_,O){var M;if(!D)return $;if(typeof D=="string"){var L=D.toLowerCase();E[L]&&(M=L),_&&(E[L]=_,M=L);var A=D.split("-");if(!M&&A.length>1)return T(A[0])}else{var B=D.name;E[B]=D,M=B}return!O&&M&&($=M),M||!O&&$},N=function(T,D){if(R(T))return T.clone();var _=typeof D=="object"?D:{};return _.date=T,_.args=arguments,new z(_)},I=x;I.l=P,I.i=R,I.w=function(T,D){return N(T,{locale:D.$L,utc:D.$u,x:D.$x,$offset:D.$offset})};var z=function(){function T(_){this.$L=P(_.locale,null,!0),this.parse(_),this.$x=this.$x||_.x||{},this[w]=!0}var D=T.prototype;return D.parse=function(_){this.$d=function(O){var M=O.date,L=O.utc;if(M===null)return new Date(NaN);if(I.u(M))return new Date;if(M instanceof Date)return new Date(M);if(typeof M=="string"&&!/Z$/i.test(M)){var A=M.match(b);if(A){var B=A[2]-1||0,k=(A[7]||"0").substring(0,3);return L?new Date(Date.UTC(A[1],B,A[3]||1,A[4]||0,A[5]||0,A[6]||0,k)):new Date(A[1],B,A[3]||1,A[4]||0,A[5]||0,A[6]||0,k)}}return new Date(M)}(_),this.init()},D.init=function(){var _=this.$d;this.$y=_.getFullYear(),this.$M=_.getMonth(),this.$D=_.getDate(),this.$W=_.getDay(),this.$H=_.getHours(),this.$m=_.getMinutes(),this.$s=_.getSeconds(),this.$ms=_.getMilliseconds()},D.$utils=function(){return I},D.isValid=function(){return this.$d.toString()!==p},D.isSame=function(_,O){var M=N(_);return this.startOf(O)<=M&&M<=this.endOf(O)},D.isAfter=function(_,O){return N(_)25){var u=a(this).startOf(r).add(1,r).date(c),d=a(this).endOf(n);if(u.isBefore(d))return 1}var v=a(this).startOf(r).date(c).startOf(n).subtract(1,"millisecond"),h=this.diff(v,n,!0);return h<0?a(this).startOf("week").week():Math.ceil(h)},l.weeks=function(s){return s===void 0&&(s=null),this.week(s)}}})})(_2);const kL=_2.exports;var A2={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){return function(n,r){r.prototype.weekYear=function(){var o=this.month(),i=this.week(),a=this.year();return i===1&&o===11?a+1:o===0&&i>=52?a-1:a}}})})(A2);const BL=A2.exports;var D2={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){return function(n,r){var o=r.prototype,i=o.format;o.format=function(a){var l=this,s=this.$locale();if(!this.isValid())return i.bind(this)(a);var c=this.$utils(),u=(a||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,function(d){switch(d){case"Q":return Math.ceil((l.$M+1)/3);case"Do":return s.ordinal(l.$D);case"gggg":return l.weekYear();case"GGGG":return l.isoWeekYear();case"wo":return s.ordinal(l.week(),"W");case"w":case"ww":return c.s(l.week(),d==="w"?1:2,"0");case"W":case"WW":return c.s(l.isoWeek(),d==="W"?1:2,"0");case"k":case"kk":return c.s(String(l.$H===0?24:l.$H),d==="k"?1:2,"0");case"X":return Math.floor(l.$d.getTime()/1e3);case"x":return l.$d.getTime();case"z":return"["+l.offsetName()+"]";case"zzz":return"["+l.offsetName("long")+"]";default:return d}});return i.bind(this)(u)}}})})(D2);const jL=D2.exports;var L2={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},r=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|YYYY|YY?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,o=/\d\d/,i=/\d\d?/,a=/\d*[^-_:/,()\s\d]+/,l={},s=function(p){return(p=+p)+(p>68?1900:2e3)},c=function(p){return function(b){this[p]=+b}},u=[/[+-]\d\d:?(\d\d)?|Z/,function(p){(this.zone||(this.zone={})).offset=function(b){if(!b||b==="Z")return 0;var m=b.match(/([+-]|\d\d)/g),y=60*m[1]+(+m[2]||0);return y===0?0:m[0]==="+"?-y:y}(p)}],d=function(p){var b=l[p];return b&&(b.indexOf?b:b.s.concat(b.f))},v=function(p,b){var m,y=l.meridiem;if(y){for(var S=1;S<=24;S+=1)if(p.indexOf(y(S,0,b))>-1){m=S>12;break}}else m=p===(b?"pm":"PM");return m},h={A:[a,function(p){this.afternoon=v(p,!1)}],a:[a,function(p){this.afternoon=v(p,!0)}],S:[/\d/,function(p){this.milliseconds=100*+p}],SS:[o,function(p){this.milliseconds=10*+p}],SSS:[/\d{3}/,function(p){this.milliseconds=+p}],s:[i,c("seconds")],ss:[i,c("seconds")],m:[i,c("minutes")],mm:[i,c("minutes")],H:[i,c("hours")],h:[i,c("hours")],HH:[i,c("hours")],hh:[i,c("hours")],D:[i,c("day")],DD:[o,c("day")],Do:[a,function(p){var b=l.ordinal,m=p.match(/\d+/);if(this.day=m[0],b)for(var y=1;y<=31;y+=1)b(y).replace(/\[|\]/g,"")===p&&(this.day=y)}],M:[i,c("month")],MM:[o,c("month")],MMM:[a,function(p){var b=d("months"),m=(d("monthsShort")||b.map(function(y){return y.slice(0,3)})).indexOf(p)+1;if(m<1)throw new Error;this.month=m%12||m}],MMMM:[a,function(p){var b=d("months").indexOf(p)+1;if(b<1)throw new Error;this.month=b%12||b}],Y:[/[+-]?\d+/,c("year")],YY:[o,function(p){this.year=s(p)}],YYYY:[/\d{4}/,c("year")],Z:u,ZZ:u};function g(p){var b,m;b=p,m=l&&l.formats;for(var y=(p=b.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,function(P,N,I){var z=I&&I.toUpperCase();return N||m[I]||n[I]||m[z].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(F,T,D){return T||D.slice(1)})})).match(r),S=y.length,x=0;x-1)return new Date((O==="X"?1e3:1)*_);var L=g(O)(_),A=L.year,B=L.month,k=L.day,j=L.hours,H=L.minutes,W=L.seconds,Y=L.milliseconds,K=L.zone,q=new Date,ee=k||(A||B?1:q.getDate()),Z=A||q.getFullYear(),Q=0;A&&!B||(Q=B>0?B-1:q.getMonth());var ne=j||0,ae=H||0,J=W||0,re=Y||0;return K?new Date(Date.UTC(Z,Q,ee,ne,ae,J,re+60*K.offset*1e3)):M?new Date(Date.UTC(Z,Q,ee,ne,ae,J,re)):new Date(Z,Q,ee,ne,ae,J,re)}catch{return new Date("")}}($,R,E),this.init(),z&&z!==!0&&(this.$L=this.locale(z).$L),I&&$!=this.format(R)&&(this.$d=new Date("")),l={}}else if(R instanceof Array)for(var F=R.length,T=1;T<=F;T+=1){w[1]=R[T-1];var D=m.apply(this,w);if(D.isValid()){this.$d=D.$d,this.$L=D.$L,this.init();break}T===F&&(this.$d=new Date(""))}else S.call(this,x)}}})})(L2);const HL=L2.exports;Lt.extend(HL);Lt.extend(jL);Lt.extend(zL);Lt.extend(FL);Lt.extend(kL);Lt.extend(BL);Lt.extend(function(e,t){var n=t.prototype,r=n.format;n.format=function(i){var a=(i||"").replace("Wo","wo");return r.bind(this)(a)}});var WL={bn_BD:"bn-bd",by_BY:"be",en_GB:"en-gb",en_US:"en",fr_BE:"fr",fr_CA:"fr-ca",hy_AM:"hy-am",kmr_IQ:"ku",nl_BE:"nl-be",pt_BR:"pt-br",zh_CN:"zh-cn",zh_HK:"zh-hk",zh_TW:"zh-tw"},ci=function(t){var n=WL[t];return n||t.split("_")[0]},Hb=function(){nx(!1,"Not match any format. Please help to fire a issue about this.")},VL={getNow:function(){return Lt()},getFixedDate:function(t){return Lt(t,["YYYY-M-DD","YYYY-MM-DD"])},getEndDate:function(t){return t.endOf("month")},getWeekDay:function(t){var n=t.locale("en");return n.weekday()+n.localeData().firstDayOfWeek()},getYear:function(t){return t.year()},getMonth:function(t){return t.month()},getDate:function(t){return t.date()},getHour:function(t){return t.hour()},getMinute:function(t){return t.minute()},getSecond:function(t){return t.second()},getMillisecond:function(t){return t.millisecond()},addYear:function(t,n){return t.add(n,"year")},addMonth:function(t,n){return t.add(n,"month")},addDate:function(t,n){return t.add(n,"day")},setYear:function(t,n){return t.year(n)},setMonth:function(t,n){return t.month(n)},setDate:function(t,n){return t.date(n)},setHour:function(t,n){return t.hour(n)},setMinute:function(t,n){return t.minute(n)},setSecond:function(t,n){return t.second(n)},setMillisecond:function(t,n){return t.millisecond(n)},isAfter:function(t,n){return t.isAfter(n)},isValidate:function(t){return t.isValid()},locale:{getWeekFirstDay:function(t){return Lt().locale(ci(t)).localeData().firstDayOfWeek()},getWeekFirstDate:function(t,n){return n.locale(ci(t)).weekday(0)},getWeek:function(t,n){return n.locale(ci(t)).week()},getShortWeekDays:function(t){return Lt().locale(ci(t)).localeData().weekdaysMin()},getShortMonths:function(t){return Lt().locale(ci(t)).localeData().monthsShort()},format:function(t,n,r){return n.locale(ci(t)).format(r)},parse:function(t,n,r){for(var o=ci(t),i=0;i2&&arguments[2]!==void 0?arguments[2]:"0",r=String(e);r.length1&&(a=t.addDate(a,-7)),a}function mn(e,t){var n=t.generateConfig,r=t.locale,o=t.format;return e?typeof o=="function"?o(e):n.locale.format(r.locale,e,o):""}function Vb(e,t,n){var r=t,o=["getHour","getMinute","getSecond","getMillisecond"],i=["setHour","setMinute","setSecond","setMillisecond"];return i.forEach(function(a,l){n?r=e[a](r,e[o[l]](n)):r=e[a](r,0)}),r}function oz(e,t,n,r,o,i){var a=e;function l(d,v,h){var g=i[d](a),p=h.find(function(S){return S.value===g});if(!p||p.disabled){var b=h.filter(function(S){return!S.disabled}),m=Oe(b).reverse(),y=m.find(function(S){return S.value<=g})||b[0];y&&(g=y.value,a=i[v](a,g))}return g}var s=l("getHour","setHour",t()),c=l("getMinute","setMinute",n(s)),u=l("getSecond","setSecond",r(s,c));return l("getMillisecond","setMillisecond",o(s,c,u)),a}function Dc(){return[]}function Lc(e,t){for(var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:1,r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1,o=arguments.length>4&&arguments[4]!==void 0?arguments[4]:[],i=arguments.length>5&&arguments[5]!==void 0?arguments[5]:2,a=[],l=n>=1?n|0:1,s=e;s<=t;s+=l){var c=o.includes(s);(!c||!r)&&a.push({label:z2(s,i),value:s,disabled:c})}return a}function H2(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=t||{},o=r.use12Hours,i=r.hourStep,a=i===void 0?1:i,l=r.minuteStep,s=l===void 0?1:l,c=r.secondStep,u=c===void 0?1:c,d=r.millisecondStep,v=d===void 0?100:d,h=r.hideDisabledOptions,g=r.disabledTime,p=r.disabledHours,b=r.disabledMinutes,m=r.disabledSeconds,y=f.exports.useMemo(function(){return n||e.getNow()},[n,e]),S=f.exports.useCallback(function(M){var L=(g==null?void 0:g(M))||{};return[L.disabledHours||p||Dc,L.disabledMinutes||b||Dc,L.disabledSeconds||m||Dc,L.disabledMilliseconds||Dc]},[g,p,b,m]),x=f.exports.useMemo(function(){return S(y)},[y,S]),$=G(x,4),E=$[0],w=$[1],R=$[2],P=$[3],N=f.exports.useCallback(function(M,L,A,B){var k=Lc(0,23,a,h,M()),j=o?k.map(function(K){return U(U({},K),{},{label:z2(K.value%12||12,2)})}):k,H=function(q){return Lc(0,59,s,h,L(q))},W=function(q,ee){return Lc(0,59,u,h,A(q,ee))},Y=function(q,ee,Z){return Lc(0,999,v,h,B(q,ee,Z),3)};return[j,H,W,Y]},[h,a,o,v,s,u]),I=f.exports.useMemo(function(){return N(E,w,R,P)},[N,E,w,R,P]),z=G(I,4),F=z[0],T=z[1],D=z[2],_=z[3],O=function(L,A){var B=function(){return F},k=T,j=D,H=_;if(A){var W=S(A),Y=G(W,4),K=Y[0],q=Y[1],ee=Y[2],Z=Y[3],Q=N(K,q,ee,Z),ne=G(Q,4),ae=ne[0],J=ne[1],re=ne[2],fe=ne[3];B=function(){return ae},k=J,j=re,H=fe}var ve=oz(L,B,k,j,H,e);return ve};return[O,F,T,D,_]}function iz(e,t,n){function r(o,i){var a=o.findIndex(function(s){return xi(e,t,s,i,n)});if(a===-1)return[].concat(Oe(o),[i]);var l=Oe(o);return l.splice(a,1),l}return r}var Hi=f.exports.createContext(null);function df(){return f.exports.useContext(Hi)}function il(e,t){var n=e.prefixCls,r=e.generateConfig,o=e.locale,i=e.disabledDate,a=e.minDate,l=e.maxDate,s=e.cellRender,c=e.hoverValue,u=e.hoverRangeValue,d=e.onHover,v=e.values,h=e.pickerValue,g=e.onSelect,p=e.prevIcon,b=e.nextIcon,m=e.superPrevIcon,y=e.superNextIcon,S=r.getNow(),x={now:S,values:v,pickerValue:h,prefixCls:n,disabledDate:i,minDate:a,maxDate:l,cellRender:s,hoverValue:c,hoverRangeValue:u,onHover:d,locale:o,generateConfig:r,onSelect:g,panelType:t,prevIcon:p,nextIcon:b,superPrevIcon:m,superNextIcon:y};return[x,S]}var Ps=f.exports.createContext({});function Zs(e){for(var t=e.rowNum,n=e.colNum,r=e.baseDate,o=e.getCellDate,i=e.prefixColumn,a=e.rowClassName,l=e.titleFormat,s=e.getCellText,c=e.getCellClassName,u=e.headerCells,d=e.cellSelection,v=d===void 0?!0:d,h=e.disabledDate,g=df(),p=g.prefixCls,b=g.panelType,m=g.now,y=g.disabledDate,S=g.cellRender,x=g.onHover,$=g.hoverValue,E=g.hoverRangeValue,w=g.generateConfig,R=g.values,P=g.locale,N=g.onSelect,I=h||y,z="".concat(p,"-cell"),F=f.exports.useContext(Ps),T=F.onCellDblClick,D=function(j){return R.some(function(H){return H&&xi(w,P,j,H,b)})},_=[],O=0;O1&&arguments[1]!==void 0?arguments[1]:!1;Ce(Ee),b==null||b(Ee),_e&&ce(Ee)},xe=function(Ee,_e){ee(Ee),_e&&de(_e),ce(_e,Ee)},he=function(Ee){if(pe(Ee),de(Ee),q!==x){var _e=["decade","year"],Be=[].concat(_e,["month"]),qe={quarter:[].concat(_e,["quarter"]),week:[].concat(Oe(Be),["week"]),date:[].concat(Oe(Be),["date"])},it=qe[x]||Be,ft=it.indexOf(q),ut=it[ft+1];ut&&xe(ut,Ee)}},ke=f.exports.useMemo(function(){var Ne,Ee;if(Array.isArray(w)){var _e=G(w,2);Ne=_e[0],Ee=_e[1]}else Ne=w;return!Ne&&!Ee?null:(Ne=Ne||Ee,Ee=Ee||Ne,o.isAfter(Ne,Ee)?[Ee,Ne]:[Ne,Ee])},[w,o]),we=GL(R,P,N),ge=z[Z]||hz[Z]||ff,Pe=f.exports.useContext(Ps),Se=f.exports.useMemo(function(){return U(U({},Pe),{},{hideHeader:F})},[Pe,F]),st="".concat(T,"-panel"),nt=k2(e,["showWeek","prevIcon","nextIcon","superPrevIcon","superNextIcon","disabledDate","minDate","maxDate","onHover"]);return C(Ps.Provider,{value:Se,children:C("div",{ref:D,tabIndex:s,className:te(st,V({},"".concat(st,"-rtl"),i==="rtl")),children:C(ge,{...nt,showTime:H,prefixCls:T,locale:k,generateConfig:o,onModeChange:xe,pickerValue:le,onPickerValueChange:function(Ee){de(Ee,!0)},value:fe[0],onSelect:he,values:fe,cellRender:we,hoverRangeValue:ke,hoverValue:E})})})}var yz=f.exports.memo(f.exports.forwardRef(mz));const V2=f.exports.createContext(null),bz=V2.Provider,U2=f.exports.createContext(null),Sz=U2.Provider;var Cz=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],xz=f.exports.forwardRef(function(e,t){var n,r=e.prefixCls,o=r===void 0?"rc-checkbox":r,i=e.className,a=e.style,l=e.checked,s=e.disabled,c=e.defaultChecked,u=c===void 0?!1:c,d=e.type,v=d===void 0?"checkbox":d,h=e.title,g=e.onChange,p=Je(e,Cz),b=f.exports.useRef(null),m=kt(u,{value:l}),y=G(m,2),S=y[0],x=y[1];f.exports.useImperativeHandle(t,function(){return{focus:function(){var R;(R=b.current)===null||R===void 0||R.focus()},blur:function(){var R;(R=b.current)===null||R===void 0||R.blur()},input:b.current}});var $=te(o,i,(n={},V(n,"".concat(o,"-checked"),S),V(n,"".concat(o,"-disabled"),s),n)),E=function(R){s||("checked"in e||x(R.target.checked),g==null||g({target:U(U({},e),{},{type:v,checked:R.target.checked}),stopPropagation:function(){R.stopPropagation()},preventDefault:function(){R.preventDefault()},nativeEvent:R.nativeEvent}))};return ie("span",{className:$,title:h,style:a,children:[C("input",{...p,className:"".concat(o,"-input"),ref:b,onChange:E,disabled:s,checked:!!S,type:v}),C("span",{className:"".concat(o,"-inner")})]})});const wz=e=>{const{componentCls:t,antCls:n}=e,r=`${t}-group`;return{[r]:Object.assign(Object.assign({},Qt(e)),{display:"inline-block",fontSize:0,[`&${r}-rtl`]:{direction:"rtl"},[`${n}-badge ${n}-badge-count`]:{zIndex:1},[`> ${n}-badge:not(:first-child) > ${n}-button-wrapper`]:{borderInlineStart:"none"}})}},$z=e=>{const{componentCls:t,wrapperMarginInlineEnd:n,colorPrimary:r,radioSize:o,motionDurationSlow:i,motionDurationMid:a,motionEaseInOutCirc:l,colorBgContainer:s,colorBorder:c,lineWidth:u,colorBgContainerDisabled:d,colorTextDisabled:v,paddingXS:h,dotColorDisabled:g,lineType:p,radioColor:b,radioBgColor:m,calc:y}=e,S=`${t}-inner`,x=4,$=y(o).sub(y(x).mul(2)),E=y(1).mul(o).equal();return{[`${t}-wrapper`]:Object.assign(Object.assign({},Qt(e)),{display:"inline-flex",alignItems:"baseline",marginInlineStart:0,marginInlineEnd:n,cursor:"pointer",[`&${t}-wrapper-rtl`]:{direction:"rtl"},"&-disabled":{cursor:"not-allowed",color:e.colorTextDisabled},"&::after":{display:"inline-block",width:0,overflow:"hidden",content:'"\\a0"'},[`${t}-checked::after`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,width:"100%",height:"100%",border:`${X(u)} ${p} ${r}`,borderRadius:"50%",visibility:"hidden",content:'""'},[t]:Object.assign(Object.assign({},Qt(e)),{position:"relative",display:"inline-block",outline:"none",cursor:"pointer",alignSelf:"center",borderRadius:"50%"}),[`${t}-wrapper:hover &, + &:hover ${S}`]:{borderColor:r},[`${t}-input:focus-visible + ${S}`]:Object.assign({},Yh(e)),[`${t}:hover::after, ${t}-wrapper:hover &::after`]:{visibility:"visible"},[`${t}-inner`]:{"&::after":{boxSizing:"border-box",position:"absolute",insetBlockStart:"50%",insetInlineStart:"50%",display:"block",width:E,height:E,marginBlockStart:y(1).mul(o).div(-2).equal(),marginInlineStart:y(1).mul(o).div(-2).equal(),backgroundColor:b,borderBlockStart:0,borderInlineStart:0,borderRadius:E,transform:"scale(0)",opacity:0,transition:`all ${i} ${l}`,content:'""'},boxSizing:"border-box",position:"relative",insetBlockStart:0,insetInlineStart:0,display:"block",width:E,height:E,backgroundColor:s,borderColor:c,borderStyle:"solid",borderWidth:u,borderRadius:"50%",transition:`all ${a}`},[`${t}-input`]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0},[`${t}-checked`]:{[S]:{borderColor:r,backgroundColor:m,"&::after":{transform:`scale(${e.calc(e.dotSize).div(o).equal()})`,opacity:1,transition:`all ${i} ${l}`}}},[`${t}-disabled`]:{cursor:"not-allowed",[S]:{backgroundColor:d,borderColor:c,cursor:"not-allowed","&::after":{backgroundColor:g}},[`${t}-input`]:{cursor:"not-allowed"},[`${t}-disabled + span`]:{color:v,cursor:"not-allowed"},[`&${t}-checked`]:{[S]:{"&::after":{transform:`scale(${y($).div(o).equal({unit:!1})})`}}}},[`span${t} + *`]:{paddingInlineStart:h,paddingInlineEnd:h}})}},Ez=e=>{const{buttonColor:t,controlHeight:n,componentCls:r,lineWidth:o,lineType:i,colorBorder:a,motionDurationSlow:l,motionDurationMid:s,buttonPaddingInline:c,fontSize:u,buttonBg:d,fontSizeLG:v,controlHeightLG:h,controlHeightSM:g,paddingXS:p,borderRadius:b,borderRadiusSM:m,borderRadiusLG:y,buttonCheckedBg:S,buttonSolidCheckedColor:x,colorTextDisabled:$,colorBgContainerDisabled:E,buttonCheckedBgDisabled:w,buttonCheckedColorDisabled:R,colorPrimary:P,colorPrimaryHover:N,colorPrimaryActive:I,buttonSolidCheckedBg:z,buttonSolidCheckedHoverBg:F,buttonSolidCheckedActiveBg:T,calc:D}=e;return{[`${r}-button-wrapper`]:{position:"relative",display:"inline-block",height:n,margin:0,paddingInline:c,paddingBlock:0,color:t,fontSize:u,lineHeight:X(D(n).sub(D(o).mul(2)).equal()),background:d,border:`${X(o)} ${i} ${a}`,borderBlockStartWidth:D(o).add(.02).equal(),borderInlineStartWidth:0,borderInlineEndWidth:o,cursor:"pointer",transition:[`color ${s}`,`background ${s}`,`box-shadow ${s}`].join(","),a:{color:t},[`> ${r}-button`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,zIndex:-1,width:"100%",height:"100%"},"&:not(:first-child)":{"&::before":{position:"absolute",insetBlockStart:D(o).mul(-1).equal(),insetInlineStart:D(o).mul(-1).equal(),display:"block",boxSizing:"content-box",width:1,height:"100%",paddingBlock:o,paddingInline:0,backgroundColor:a,transition:`background-color ${l}`,content:'""'}},"&:first-child":{borderInlineStart:`${X(o)} ${i} ${a}`,borderStartStartRadius:b,borderEndStartRadius:b},"&:last-child":{borderStartEndRadius:b,borderEndEndRadius:b},"&:first-child:last-child":{borderRadius:b},[`${r}-group-large &`]:{height:h,fontSize:v,lineHeight:X(D(h).sub(D(o).mul(2)).equal()),"&:first-child":{borderStartStartRadius:y,borderEndStartRadius:y},"&:last-child":{borderStartEndRadius:y,borderEndEndRadius:y}},[`${r}-group-small &`]:{height:g,paddingInline:D(p).sub(o).equal(),paddingBlock:0,lineHeight:X(D(g).sub(D(o).mul(2)).equal()),"&:first-child":{borderStartStartRadius:m,borderEndStartRadius:m},"&:last-child":{borderStartEndRadius:m,borderEndEndRadius:m}},"&:hover":{position:"relative",color:P},"&:has(:focus-visible)":Object.assign({},Yh(e)),[`${r}-inner, input[type='checkbox'], input[type='radio']`]:{width:0,height:0,opacity:0,pointerEvents:"none"},[`&-checked:not(${r}-button-wrapper-disabled)`]:{zIndex:1,color:P,background:S,borderColor:P,"&::before":{backgroundColor:P},"&:first-child":{borderColor:P},"&:hover":{color:N,borderColor:N,"&::before":{backgroundColor:N}},"&:active":{color:I,borderColor:I,"&::before":{backgroundColor:I}}},[`${r}-group-solid &-checked:not(${r}-button-wrapper-disabled)`]:{color:x,background:z,borderColor:z,"&:hover":{color:x,background:F,borderColor:F},"&:active":{color:x,background:T,borderColor:T}},"&-disabled":{color:$,backgroundColor:E,borderColor:a,cursor:"not-allowed","&:first-child, &:hover":{color:$,backgroundColor:E,borderColor:a}},[`&-disabled${r}-button-wrapper-checked`]:{color:R,backgroundColor:w,borderColor:a,boxShadow:"none"}}}},Mz=e=>{const{wireframe:t,padding:n,marginXS:r,lineWidth:o,fontSizeLG:i,colorText:a,colorBgContainer:l,colorTextDisabled:s,controlItemBgActiveDisabled:c,colorTextLightSolid:u,colorPrimary:d,colorPrimaryHover:v,colorPrimaryActive:h,colorWhite:g}=e,p=4,b=i,m=t?b-p*2:b-(p+o)*2;return{radioSize:b,dotSize:m,dotColorDisabled:s,buttonSolidCheckedColor:u,buttonSolidCheckedBg:d,buttonSolidCheckedHoverBg:v,buttonSolidCheckedActiveBg:h,buttonBg:l,buttonCheckedBg:l,buttonColor:a,buttonCheckedBgDisabled:c,buttonCheckedColorDisabled:s,buttonPaddingInline:n-o,wrapperMarginInlineEnd:r,radioColor:t?d:g,radioBgColor:t?l:d}},Y2=vn("Radio",e=>{const{controlOutline:t,controlOutlineWidth:n}=e,r=`0 0 0 ${X(n)} ${t}`,i=$t(e,{radioFocusShadow:r,radioButtonFocusShadow:r});return[wz(i),$z(i),Ez(i)]},Mz,{unitless:{radioSize:!0,dotSize:!0}});var Oz=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n,r;const o=f.exports.useContext(V2),i=f.exports.useContext(U2),{getPrefixCls:a,direction:l,radio:s}=f.exports.useContext(ot),c=f.exports.useRef(null),u=xr(t,c),{isFormItemInput:d}=f.exports.useContext(Jr),v=T=>{var D,_;(D=e.onChange)===null||D===void 0||D.call(e,T),(_=o==null?void 0:o.onChange)===null||_===void 0||_.call(o,T)},{prefixCls:h,className:g,rootClassName:p,children:b,style:m,title:y}=e,S=Oz(e,["prefixCls","className","rootClassName","children","style","title"]),x=a("radio",h),$=((o==null?void 0:o.optionType)||i)==="button",E=$?`${x}-button`:x,w=no(x),[R,P,N]=Y2(x,w),I=Object.assign({},S),z=f.exports.useContext(rl);o&&(I.name=o.name,I.onChange=v,I.checked=e.value===o.value,I.disabled=(n=I.disabled)!==null&&n!==void 0?n:o.disabled),I.disabled=(r=I.disabled)!==null&&r!==void 0?r:z;const F=te(`${E}-wrapper`,{[`${E}-wrapper-checked`]:I.checked,[`${E}-wrapper-disabled`]:I.disabled,[`${E}-wrapper-rtl`]:l==="rtl",[`${E}-wrapper-in-form-item`]:d},s==null?void 0:s.className,g,p,P,N,w);return R(C(Qh,{component:"Radio",disabled:I.disabled,children:ie("label",{className:F,style:Object.assign(Object.assign({},s==null?void 0:s.style),m),onMouseEnter:e.onMouseEnter,onMouseLeave:e.onMouseLeave,title:y,children:[C(xz,{...Object.assign({},I,{className:te(I.className,!$&&Xh),type:"radio",prefixCls:E,ref:u})}),b!==void 0?C("span",{children:b}):null]})}))},Iz=f.exports.forwardRef(Rz),rd=Iz,Pz=f.exports.forwardRef((e,t)=>{const{getPrefixCls:n,direction:r}=f.exports.useContext(ot),[o,i]=kt(e.defaultValue,{value:e.value}),a=T=>{const D=o,_=T.target.value;"value"in e||i(_);const{onChange:O}=e;O&&_!==D&&O(T)},{prefixCls:l,className:s,rootClassName:c,options:u,buttonStyle:d="outline",disabled:v,children:h,size:g,style:p,id:b,onMouseEnter:m,onMouseLeave:y,onFocus:S,onBlur:x}=e,$=n("radio",l),E=`${$}-group`,w=no($),[R,P,N]=Y2($,w);let I=h;u&&u.length>0&&(I=u.map(T=>typeof T=="string"||typeof T=="number"?C(rd,{prefixCls:$,disabled:v,value:T,checked:o===T,children:T},T.toString()):C(rd,{prefixCls:$,disabled:T.disabled||v,value:T.value,checked:o===T.value,title:T.title,style:T.style,id:T.id,required:T.required,children:T.label},`radio-group-value-options-${T.value}`)));const z=So(g),F=te(E,`${E}-${d}`,{[`${E}-${z}`]:z,[`${E}-rtl`]:r==="rtl"},s,c,P,N,w);return R(C("div",{...Object.assign({},Ka(e,{aria:!0,data:!0}),{className:F,style:p,onMouseEnter:m,onMouseLeave:y,onFocus:S,onBlur:x,id:b,ref:t}),children:C(bz,{value:{onChange:a,value:o,disabled:e.disabled,name:e.name,optionType:e.optionType},children:I})}))}),G2=f.exports.memo(Pz);var Tz=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{getPrefixCls:n}=f.exports.useContext(ot),{prefixCls:r}=e,o=Tz(e,["prefixCls"]),i=n("radio",r);return C(Sz,{value:"button",children:C(rd,{...Object.assign({prefixCls:i},o,{type:"radio",ref:t})})})},Ig=f.exports.forwardRef(Nz),Om=rd;Om.Button=Ig;Om.Group=G2;Om.__ANT_RADIO=!0;const _z=10,Az=20;function Dz(e){const{fullscreen:t,validRange:n,generateConfig:r,locale:o,prefixCls:i,value:a,onChange:l,divRef:s}=e,c=r.getYear(a||r.getNow());let u=c-_z,d=u+Az;n&&(u=r.getYear(n[0]),d=r.getYear(n[1])+1);const v=o&&o.year==="\u5E74"?"\u5E74":"",h=[];for(let g=u;g{let p=r.setYear(a,g);if(n){const[b,m]=n,y=r.getYear(p),S=r.getMonth(p);y===r.getYear(m)&&S>r.getMonth(m)&&(p=r.setMonth(p,r.getMonth(m))),y===r.getYear(b)&&Ss.current})}function Lz(e){const{prefixCls:t,fullscreen:n,validRange:r,value:o,generateConfig:i,locale:a,onChange:l,divRef:s}=e,c=i.getMonth(o||i.getNow());let u=0,d=11;if(r){const[g,p]=r,b=i.getYear(o);i.getYear(p)===b&&(d=i.getMonth(p)),i.getYear(g)===b&&(u=i.getMonth(g))}const v=a.shortMonths||i.locale.getShortMonths(a.locale),h=[];for(let g=u;g<=d;g+=1)h.push({label:v[g],value:g});return C(r2,{size:n?void 0:"small",className:`${t}-month-select`,value:c,options:h,onChange:g=>{l(i.setMonth(o,g))},getPopupContainer:()=>s.current})}function zz(e){const{prefixCls:t,locale:n,mode:r,fullscreen:o,onModeChange:i}=e;return ie(G2,{onChange:a=>{let{target:{value:l}}=a;i(l)},value:r,size:o?void 0:"small",className:`${t}-mode-switch`,children:[C(Ig,{value:"month",children:n.month}),C(Ig,{value:"year",children:n.year})]})}function Fz(e){const{prefixCls:t,fullscreen:n,mode:r,onChange:o,onModeChange:i}=e,a=f.exports.useRef(null),l=f.exports.useContext(Jr),s=f.exports.useMemo(()=>Object.assign(Object.assign({},l),{isFormItemInput:!1}),[l]),c=Object.assign(Object.assign({},e),{fullscreen:n,divRef:a});return ie("div",{className:`${t}-header`,ref:a,children:[ie(Jr.Provider,{value:s,children:[C(Dz,{...Object.assign({},c,{onChange:u=>{o(u,"year")}})}),r==="month"&&C(Lz,{...Object.assign({},c,{onChange:u=>{o(u,"month")}})})]}),C(zz,{...Object.assign({},c,{onModeChange:i})})]})}function K2(e){return $t(e,{inputAffixPadding:e.paddingXXS})}const q2=e=>{const{controlHeight:t,fontSize:n,lineHeight:r,lineWidth:o,controlHeightSM:i,controlHeightLG:a,fontSizeLG:l,lineHeightLG:s,paddingSM:c,controlPaddingHorizontalSM:u,controlPaddingHorizontal:d,colorFillAlter:v,colorPrimaryHover:h,colorPrimary:g,controlOutlineWidth:p,controlOutline:b,colorErrorOutline:m,colorWarningOutline:y,colorBgContainer:S}=e;return{paddingBlock:Math.max(Math.round((t-n*r)/2*10)/10-o,0),paddingBlockSM:Math.max(Math.round((i-n*r)/2*10)/10-o,0),paddingBlockLG:Math.ceil((a-l*s)/2*10)/10-o,paddingInline:c-o,paddingInlineSM:u-o,paddingInlineLG:d-o,addonBg:v,activeBorderColor:g,hoverBorderColor:h,activeShadow:`0 0 0 ${p}px ${b}`,errorActiveShadow:`0 0 0 ${p}px ${m}`,warningActiveShadow:`0 0 0 ${p}px ${y}`,hoverBg:S,activeBg:S,inputFontSize:n,inputFontSizeLG:l,inputFontSizeSM:n}},kz=e=>({borderColor:e.hoverBorderColor,backgroundColor:e.hoverBg}),Rm=e=>({color:e.colorTextDisabled,backgroundColor:e.colorBgContainerDisabled,borderColor:e.colorBorder,boxShadow:"none",cursor:"not-allowed",opacity:1,"input[disabled]":{cursor:"not-allowed"},"&:hover:not([disabled])":Object.assign({},kz($t(e,{hoverBorderColor:e.colorBorder,hoverBg:e.colorBgContainerDisabled})))}),X2=(e,t)=>({background:e.colorBgContainer,borderWidth:e.lineWidth,borderStyle:e.lineType,borderColor:t.borderColor,"&:hover":{borderColor:t.hoverBorderColor,backgroundColor:e.hoverBg},"&:focus, &:focus-within":{borderColor:t.activeBorderColor,boxShadow:t.activeShadow,outline:0,backgroundColor:e.activeBg}}),Ub=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},X2(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}})}),Q2=(e,t)=>({"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},X2(e,{borderColor:e.colorBorder,hoverBorderColor:e.hoverBorderColor,activeBorderColor:e.activeBorderColor,activeShadow:e.activeShadow})),{[`&${e.componentCls}-disabled, &[disabled]`]:Object.assign({},Rm(e))}),Ub(e,{status:"error",borderColor:e.colorError,hoverBorderColor:e.colorErrorBorderHover,activeBorderColor:e.colorError,activeShadow:e.errorActiveShadow,affixColor:e.colorError})),Ub(e,{status:"warning",borderColor:e.colorWarning,hoverBorderColor:e.colorWarningBorderHover,activeBorderColor:e.colorWarning,activeShadow:e.warningActiveShadow,affixColor:e.colorWarning})),t)}),Yb=(e,t)=>({[`&${e.componentCls}-group-wrapper-status-${t.status}`]:{[`${e.componentCls}-group-addon`]:{borderColor:t.addonBorderColor,color:t.addonColor}}}),Bz=e=>({"&-outlined":Object.assign(Object.assign(Object.assign({[`${e.componentCls}-group`]:{"&-addon":{background:e.addonBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},"&-addon:first-child":{borderInlineEnd:0},"&-addon:last-child":{borderInlineStart:0}}},Yb(e,{status:"error",addonBorderColor:e.colorError,addonColor:e.colorErrorText})),Yb(e,{status:"warning",addonBorderColor:e.colorWarning,addonColor:e.colorWarningText})),{[`&${e.componentCls}-group-wrapper-disabled`]:{[`${e.componentCls}-group-addon`]:Object.assign({},Rm(e))}})}),Z2=(e,t)=>({"&-borderless":Object.assign({background:"transparent",border:"none","&:focus, &:focus-within":{outline:"none"},[`&${e.componentCls}-disabled, &[disabled]`]:{color:e.colorTextDisabled}},t)}),J2=(e,t)=>({background:t.bg,borderWidth:e.lineWidth,borderStyle:e.lineType,borderColor:"transparent",["input&, & input, textarea&, & textarea"]:{color:t==null?void 0:t.inputColor},"&:hover":{background:t.hoverBg},"&:focus, &:focus-within":{outline:0,borderColor:t.activeBorderColor,backgroundColor:e.activeBg}}),Gb=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},J2(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}})}),e$=(e,t)=>({"&-filled":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},J2(e,{bg:e.colorFillTertiary,hoverBg:e.colorFillSecondary,activeBorderColor:e.colorPrimary})),{[`&${e.componentCls}-disabled, &[disabled]`]:Object.assign({},Rm(e))}),Gb(e,{status:"error",bg:e.colorErrorBg,hoverBg:e.colorErrorBgHover,activeBorderColor:e.colorError,inputColor:e.colorErrorText,affixColor:e.colorError})),Gb(e,{status:"warning",bg:e.colorWarningBg,hoverBg:e.colorWarningBgHover,activeBorderColor:e.colorWarning,inputColor:e.colorWarningText,affixColor:e.colorWarning})),t)}),Kb=(e,t)=>({[`&${e.componentCls}-group-wrapper-status-${t.status}`]:{[`${e.componentCls}-group-addon`]:{background:t.addonBg,color:t.addonColor}}}),jz=e=>({"&-filled":Object.assign(Object.assign(Object.assign({[`${e.componentCls}-group`]:{"&-addon":{background:e.colorFillTertiary},[`${e.componentCls}-filled:not(:focus):not(:focus-within)`]:{"&:not(:first-child)":{borderInlineStart:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`},"&:not(:last-child)":{borderInlineEnd:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`}}}},Kb(e,{status:"error",addonBg:e.colorErrorBg,addonColor:e.colorErrorText})),Kb(e,{status:"warning",addonBg:e.colorWarningBg,addonColor:e.colorWarningText})),{[`&${e.componentCls}-group-wrapper-disabled`]:{[`${e.componentCls}-group`]:{"&-addon":{background:e.colorFillTertiary,color:e.colorTextDisabled},"&-addon:first-child":{borderInlineStart:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderTop:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},"&-addon:last-child":{borderInlineEnd:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderTop:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`}}}})}),t$=e=>({"&::-moz-placeholder":{opacity:1},"&::placeholder":{color:e,userSelect:"none"},"&:placeholder-shown":{textOverflow:"ellipsis"}}),n$=e=>{const{paddingBlockLG:t,lineHeightLG:n,borderRadiusLG:r,paddingInlineLG:o}=e;return{padding:`${X(t)} ${X(o)}`,fontSize:e.inputFontSizeLG,lineHeight:n,borderRadius:r}},r$=e=>({padding:`${X(e.paddingBlockSM)} ${X(e.paddingInlineSM)}`,fontSize:e.inputFontSizeSM,borderRadius:e.borderRadiusSM}),o$=e=>Object.assign(Object.assign({position:"relative",display:"inline-block",width:"100%",minWidth:0,padding:`${X(e.paddingBlock)} ${X(e.paddingInline)}`,color:e.colorText,fontSize:e.inputFontSize,lineHeight:e.lineHeight,borderRadius:e.borderRadius,transition:`all ${e.motionDurationMid}`},t$(e.colorTextPlaceholder)),{"textarea&":{maxWidth:"100%",height:"auto",minHeight:e.controlHeight,lineHeight:e.lineHeight,verticalAlign:"bottom",transition:`all ${e.motionDurationSlow}, height 0s`,resize:"vertical"},"&-lg":Object.assign({},n$(e)),"&-sm":Object.assign({},r$(e)),"&-rtl":{direction:"rtl"},"&-textarea-rtl":{direction:"rtl"}}),Hz=e=>{const{componentCls:t,antCls:n}=e;return{position:"relative",display:"table",width:"100%",borderCollapse:"separate",borderSpacing:0,["&[class*='col-']"]:{paddingInlineEnd:e.paddingXS,"&:last-child":{paddingInlineEnd:0}},[`&-lg ${t}, &-lg > ${t}-group-addon`]:Object.assign({},n$(e)),[`&-sm ${t}, &-sm > ${t}-group-addon`]:Object.assign({},r$(e)),[`&-lg ${n}-select-single ${n}-select-selector`]:{height:e.controlHeightLG},[`&-sm ${n}-select-single ${n}-select-selector`]:{height:e.controlHeightSM},[`> ${t}`]:{display:"table-cell","&:not(:first-child):not(:last-child)":{borderRadius:0}},[`${t}-group`]:{["&-addon, &-wrap"]:{display:"table-cell",width:1,whiteSpace:"nowrap",verticalAlign:"middle","&:not(:first-child):not(:last-child)":{borderRadius:0}},"&-wrap > *":{display:"block !important"},"&-addon":{position:"relative",padding:`0 ${X(e.paddingInline)}`,color:e.colorText,fontWeight:"normal",fontSize:e.inputFontSize,textAlign:"center",borderRadius:e.borderRadius,transition:`all ${e.motionDurationSlow}`,lineHeight:1,[`${n}-select`]:{margin:`${X(e.calc(e.paddingBlock).add(1).mul(-1).equal())} ${X(e.calc(e.paddingInline).mul(-1).equal())}`,[`&${n}-select-single:not(${n}-select-customize-input):not(${n}-pagination-size-changer)`]:{[`${n}-select-selector`]:{backgroundColor:"inherit",border:`${X(e.lineWidth)} ${e.lineType} transparent`,boxShadow:"none"}},"&-open, &-focused":{[`${n}-select-selector`]:{color:e.colorPrimary}}},[`${n}-cascader-picker`]:{margin:`-9px ${X(e.calc(e.paddingInline).mul(-1).equal())}`,backgroundColor:"transparent",[`${n}-cascader-input`]:{textAlign:"start",border:0,boxShadow:"none"}}}},[`${t}`]:{width:"100%",marginBottom:0,textAlign:"inherit","&:focus":{zIndex:1,borderInlineEndWidth:1},"&:hover":{zIndex:1,borderInlineEndWidth:1,[`${t}-search-with-button &`]:{zIndex:0}}},[`> ${t}:first-child, ${t}-group-addon:first-child`]:{borderStartEndRadius:0,borderEndEndRadius:0,[`${n}-select ${n}-select-selector`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`> ${t}-affix-wrapper`]:{[`&:not(:first-child) ${t}`]:{borderStartStartRadius:0,borderEndStartRadius:0},[`&:not(:last-child) ${t}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`> ${t}:last-child, ${t}-group-addon:last-child`]:{borderStartStartRadius:0,borderEndStartRadius:0,[`${n}-select ${n}-select-selector`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`${t}-affix-wrapper`]:{"&:not(:last-child)":{borderStartEndRadius:0,borderEndEndRadius:0,[`${t}-search &`]:{borderStartStartRadius:e.borderRadius,borderEndStartRadius:e.borderRadius}},[`&:not(:first-child), ${t}-search &:not(:first-child)`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`&${t}-group-compact`]:Object.assign(Object.assign({display:"block"},Us()),{[`${t}-group-addon, ${t}-group-wrap, > ${t}`]:{"&:not(:first-child):not(:last-child)":{borderInlineEndWidth:e.lineWidth,"&:hover":{zIndex:1},"&:focus":{zIndex:1}}},"& > *":{display:"inline-block",float:"none",verticalAlign:"top",borderRadius:0},[` + & > ${t}-affix-wrapper, + & > ${t}-number-affix-wrapper, + & > ${n}-picker-range + `]:{display:"inline-flex"},"& > *:not(:last-child)":{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal(),borderInlineEndWidth:e.lineWidth},[`${t}`]:{float:"none"},[`& > ${n}-select > ${n}-select-selector, + & > ${n}-select-auto-complete ${t}, + & > ${n}-cascader-picker ${t}, + & > ${t}-group-wrapper ${t}`]:{borderInlineEndWidth:e.lineWidth,borderRadius:0,"&:hover":{zIndex:1},"&:focus":{zIndex:1}},[`& > ${n}-select-focused`]:{zIndex:1},[`& > ${n}-select > ${n}-select-arrow`]:{zIndex:1},[`& > *:first-child, + & > ${n}-select:first-child > ${n}-select-selector, + & > ${n}-select-auto-complete:first-child ${t}, + & > ${n}-cascader-picker:first-child ${t}`]:{borderStartStartRadius:e.borderRadius,borderEndStartRadius:e.borderRadius},[`& > *:last-child, + & > ${n}-select:last-child > ${n}-select-selector, + & > ${n}-cascader-picker:last-child ${t}, + & > ${n}-cascader-picker-focused:last-child ${t}`]:{borderInlineEndWidth:e.lineWidth,borderStartEndRadius:e.borderRadius,borderEndEndRadius:e.borderRadius},[`& > ${n}-select-auto-complete ${t}`]:{verticalAlign:"top"},[`${t}-group-wrapper + ${t}-group-wrapper`]:{marginInlineStart:e.calc(e.lineWidth).mul(-1).equal(),[`${t}-affix-wrapper`]:{borderRadius:0}},[`${t}-group-wrapper:not(:last-child)`]:{[`&${t}-search > ${t}-group`]:{[`& > ${t}-group-addon > ${t}-search-button`]:{borderRadius:0},[`& > ${t}`]:{borderStartStartRadius:e.borderRadius,borderStartEndRadius:0,borderEndEndRadius:0,borderEndStartRadius:e.borderRadius}}}})}},Wz=e=>{const{componentCls:t,controlHeightSM:n,lineWidth:r,calc:o}=e,i=16,a=o(n).sub(o(r).mul(2)).sub(i).div(2).equal();return{[t]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),o$(e)),Q2(e)),e$(e)),Z2(e)),{'&[type="color"]':{height:e.controlHeight,[`&${t}-lg`]:{height:e.controlHeightLG},[`&${t}-sm`]:{height:n,paddingTop:a,paddingBottom:a}},'&[type="search"]::-webkit-search-cancel-button, &[type="search"]::-webkit-search-decoration':{"-webkit-appearance":"none"}})}},Vz=e=>{const{componentCls:t}=e;return{[`${t}-clear-icon`]:{margin:0,color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,verticalAlign:-1,cursor:"pointer",transition:`color ${e.motionDurationSlow}`,"&:hover":{color:e.colorTextTertiary},"&:active":{color:e.colorText},"&-hidden":{visibility:"hidden"},"&-has-suffix":{margin:`0 ${X(e.inputAffixPadding)}`}}}},Uz=e=>{const{componentCls:t,inputAffixPadding:n,colorTextDescription:r,motionDurationSlow:o,colorIcon:i,colorIconHover:a,iconCls:l}=e;return{[`${t}-affix-wrapper`]:Object.assign(Object.assign(Object.assign(Object.assign({},o$(e)),{display:"inline-flex",[`&:not(${t}-disabled):hover`]:{zIndex:1,[`${t}-search-with-button &`]:{zIndex:0}},"&-focused, &:focus":{zIndex:1},[`> input${t}`]:{padding:0,fontSize:"inherit",border:"none",borderRadius:0,outline:"none",background:"transparent",color:"inherit","&::-ms-reveal":{display:"none"},"&:focus":{boxShadow:"none !important"}},"&::before":{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'},[`${t}`]:{"&-prefix, &-suffix":{display:"flex",flex:"none",alignItems:"center","> *:not(:last-child)":{marginInlineEnd:e.paddingXS}},"&-show-count-suffix":{color:r},"&-show-count-has-suffix":{marginInlineEnd:e.paddingXXS},"&-prefix":{marginInlineEnd:n},"&-suffix":{marginInlineStart:n}}}),Vz(e)),{[`${l}${t}-password-icon`]:{color:i,cursor:"pointer",transition:`all ${o}`,"&:hover":{color:a}}})}},Yz=e=>{const{componentCls:t,borderRadiusLG:n,borderRadiusSM:r}=e;return{[`${t}-group`]:Object.assign(Object.assign(Object.assign({},Qt(e)),Hz(e)),{"&-rtl":{direction:"rtl"},"&-wrapper":Object.assign(Object.assign(Object.assign({display:"inline-block",width:"100%",textAlign:"start",verticalAlign:"top","&-rtl":{direction:"rtl"},"&-lg":{[`${t}-group-addon`]:{borderRadius:n,fontSize:e.inputFontSizeLG}},"&-sm":{[`${t}-group-addon`]:{borderRadius:r}}},Bz(e)),jz(e)),{[`&:not(${t}-compact-first-item):not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}, ${t}-group-addon`]:{borderRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-first-item`]:{[`${t}, ${t}-group-addon`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&:not(${t}-compact-first-item)${t}-compact-last-item`]:{[`${t}, ${t}-group-addon`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}-affix-wrapper`]:{borderStartEndRadius:0,borderEndEndRadius:0}}})})}},Gz=e=>{const{componentCls:t,antCls:n}=e,r=`${t}-search`;return{[r]:{[`${t}`]:{"&:hover, &:focus":{borderColor:e.colorPrimaryHover,[`+ ${t}-group-addon ${r}-button:not(${n}-btn-primary)`]:{borderInlineStartColor:e.colorPrimaryHover}}},[`${t}-affix-wrapper`]:{borderRadius:0},[`${t}-lg`]:{lineHeight:e.calc(e.lineHeightLG).sub(2e-4).equal({unit:!1})},[`> ${t}-group`]:{[`> ${t}-group-addon:last-child`]:{insetInlineStart:-1,padding:0,border:0,[`${r}-button`]:{marginInlineEnd:-1,paddingTop:0,paddingBottom:0,borderStartStartRadius:0,borderStartEndRadius:e.borderRadius,borderEndEndRadius:e.borderRadius,borderEndStartRadius:0,boxShadow:"none"},[`${r}-button:not(${n}-btn-primary)`]:{color:e.colorTextDescription,"&:hover":{color:e.colorPrimaryHover},"&:active":{color:e.colorPrimaryActive},[`&${n}-btn-loading::before`]:{insetInlineStart:0,insetInlineEnd:0,insetBlockStart:0,insetBlockEnd:0}}}},[`${r}-button`]:{height:e.controlHeight,"&:hover, &:focus":{zIndex:1}},[`&-large ${r}-button`]:{height:e.controlHeightLG},[`&-small ${r}-button`]:{height:e.controlHeightSM},"&-rtl":{direction:"rtl"},[`&${t}-compact-item`]:{[`&:not(${t}-compact-last-item)`]:{[`${t}-group-addon`]:{[`${t}-search-button`]:{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal(),borderRadius:0}}},[`&:not(${t}-compact-first-item)`]:{[`${t},${t}-affix-wrapper`]:{borderRadius:0}},[`> ${t}-group-addon ${t}-search-button, + > ${t}, + ${t}-affix-wrapper`]:{"&:hover,&:focus,&:active":{zIndex:2}},[`> ${t}-affix-wrapper-focused`]:{zIndex:2}}}}},Kz=e=>{const{componentCls:t,paddingLG:n}=e,r=`${t}-textarea`;return{[r]:{position:"relative","&-show-count":{[`> ${t}`]:{height:"100%"},[`${t}-data-count`]:{position:"absolute",bottom:e.calc(e.fontSize).mul(e.lineHeight).mul(-1).equal(),insetInlineEnd:0,color:e.colorTextDescription,whiteSpace:"nowrap",pointerEvents:"none"}},"&-allow-clear":{[`> ${t}`]:{paddingInlineEnd:n}},[`&-affix-wrapper${r}-has-feedback`]:{[`${t}`]:{paddingInlineEnd:n}},[`&-affix-wrapper${t}-affix-wrapper`]:{padding:0,[`> textarea${t}`]:{fontSize:"inherit",border:"none",outline:"none",background:"transparent","&:focus":{boxShadow:"none !important"}},[`${t}-suffix`]:{margin:0,"> *:not(:last-child)":{marginInline:0},[`${t}-clear-icon`]:{position:"absolute",insetInlineEnd:e.paddingXS,insetBlockStart:e.paddingXS},[`${r}-suffix`]:{position:"absolute",top:0,insetInlineEnd:e.paddingInline,bottom:0,zIndex:1,display:"inline-flex",alignItems:"center",margin:"auto",pointerEvents:"none"}}}}}},qz=e=>{const{componentCls:t}=e;return{[`${t}-out-of-range`]:{[`&, & input, & textarea, ${t}-show-count-suffix, ${t}-data-count`]:{color:e.colorError}}}},Im=vn("Input",e=>{const t=$t(e,K2(e));return[Wz(t),Kz(t),Uz(t),Yz(t),Gz(t),qz(t),tf(t)]},q2),bv=(e,t)=>{const{componentCls:n,selectHeight:r,fontHeight:o,lineWidth:i,calc:a}=e,l=t?`${n}-${t}`:"",s=e.calc(o).add(2).equal(),c=()=>a(r).sub(s).sub(a(i).mul(2)),u=e.max(c().div(2).equal(),0),d=e.max(c().sub(u).equal(),0);return[pm(e,t),{[`${n}-multiple${l}`]:{paddingTop:u,paddingBottom:d,paddingInlineStart:u}}]},Xz=e=>{const{componentCls:t,calc:n,lineWidth:r}=e,o=$t(e,{fontHeight:e.fontSize,selectHeight:e.controlHeightSM,multipleSelectItemHeight:e.controlHeightXS,borderRadius:e.borderRadiusSM,borderRadiusSM:e.borderRadiusXS}),i=$t(e,{fontHeight:n(e.multipleItemHeightLG).sub(n(r).mul(2).equal()).equal(),fontSize:e.fontSizeLG,selectHeight:e.controlHeightLG,multipleSelectItemHeight:e.multipleItemHeightLG,borderRadius:e.borderRadiusLG,borderRadiusSM:e.borderRadius});return[bv(o,"small"),bv(e),bv(i,"large"),pm(e),{[`${t}${t}-multiple`]:{width:"100%",[`${t}-selector`]:{flex:"auto",padding:0,"&:after":{margin:0}},[`${t}-selection-item`]:{marginBlock:0},[`${t}-multiple-input`]:{width:0,height:0,border:0,visibility:"hidden",position:"absolute",zIndex:-1}}}]},Qz=Xz,Zz=e=>{const{pickerCellCls:t,pickerCellInnerCls:n,cellHeight:r,borderRadiusSM:o,motionDurationMid:i,cellHoverBg:a,lineWidth:l,lineType:s,colorPrimary:c,cellActiveWithRangeBg:u,colorTextLightSolid:d,colorTextDisabled:v,cellBgDisabled:h,colorFillSecondary:g}=e;return{"&::before":{position:"absolute",top:"50%",insetInlineStart:0,insetInlineEnd:0,zIndex:1,height:r,transform:"translateY(-50%)",content:'""'},[n]:{position:"relative",zIndex:2,display:"inline-block",minWidth:r,height:r,lineHeight:X(r),borderRadius:o,transition:`background ${i}`},[`&:hover:not(${t}-in-view), + &:hover:not(${t}-selected):not(${t}-range-start):not(${t}-range-end)`]:{[n]:{background:a}},[`&-in-view${t}-today ${n}`]:{"&::before":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:1,border:`${X(l)} ${s} ${c}`,borderRadius:o,content:'""'}},[`&-in-view${t}-in-range, + &-in-view${t}-range-start, + &-in-view${t}-range-end`]:{position:"relative",[`&:not(${t}-disabled):before`]:{background:u}},[`&-in-view${t}-selected, + &-in-view${t}-range-start, + &-in-view${t}-range-end`]:{[`&:not(${t}-disabled) ${n}`]:{color:d,background:c},[`&${t}-disabled ${n}`]:{background:g}},[`&-in-view${t}-range-start:not(${t}-disabled):before`]:{insetInlineStart:"50%"},[`&-in-view${t}-range-end:not(${t}-disabled):before`]:{insetInlineEnd:"50%"},[`&-in-view${t}-range-start:not(${t}-range-end) ${n}`]:{borderStartStartRadius:o,borderEndStartRadius:o,borderStartEndRadius:0,borderEndEndRadius:0},[`&-in-view${t}-range-end:not(${t}-range-start) ${n}`]:{borderStartStartRadius:0,borderEndStartRadius:0,borderStartEndRadius:o,borderEndEndRadius:o},"&-disabled":{color:v,pointerEvents:"none",[n]:{background:"transparent"},"&::before":{background:h}},[`&-disabled${t}-today ${n}::before`]:{borderColor:v}}},i$=e=>{const{componentCls:t,pickerCellCls:n,pickerCellInnerCls:r,pickerYearMonthCellWidth:o,pickerControlIconSize:i,cellWidth:a,paddingSM:l,paddingXS:s,paddingXXS:c,colorBgContainer:u,lineWidth:d,lineType:v,borderRadiusLG:h,colorPrimary:g,colorTextHeading:p,colorSplit:b,pickerControlIconBorderWidth:m,colorIcon:y,textHeight:S,motionDurationMid:x,colorIconHover:$,fontWeightStrong:E,cellHeight:w,pickerCellPaddingVertical:R,colorTextDisabled:P,colorText:N,fontSize:I,motionDurationSlow:z,withoutTimeCellHeight:F,pickerQuarterPanelContentHeight:T,borderRadiusSM:D,colorTextLightSolid:_,cellHoverBg:O,timeColumnHeight:M,timeColumnWidth:L,timeCellHeight:A,controlItemBgActive:B,marginXXS:k,pickerDatePanelPaddingHorizontal:j,pickerControlIconMargin:H}=e,W=e.calc(a).mul(7).add(e.calc(j).mul(2)).equal();return{[t]:{"&-panel":{display:"inline-flex",flexDirection:"column",textAlign:"center",background:u,borderRadius:h,outline:"none","&-focused":{borderColor:g},"&-rtl":{direction:"rtl",[`${t}-prev-icon, + ${t}-super-prev-icon`]:{transform:"rotate(45deg)"},[`${t}-next-icon, + ${t}-super-next-icon`]:{transform:"rotate(-135deg)"}}},[`&-decade-panel, + &-year-panel, + &-quarter-panel, + &-month-panel, + &-week-panel, + &-date-panel, + &-time-panel`]:{display:"flex",flexDirection:"column",width:W},"&-header":{display:"flex",padding:`0 ${X(s)}`,color:p,borderBottom:`${X(d)} ${v} ${b}`,"> *":{flex:"none"},button:{padding:0,color:y,lineHeight:X(S),background:"transparent",border:0,cursor:"pointer",transition:`color ${x}`,fontSize:"inherit"},"> button":{minWidth:"1.6em",fontSize:I,"&:hover":{color:$},"&:disabled":{opacity:.25,pointerEvents:"none"}},"&-view":{flex:"auto",fontWeight:E,lineHeight:X(S),button:{color:"inherit",fontWeight:"inherit",verticalAlign:"top","&:not(:first-child)":{marginInlineStart:s},"&:hover":{color:g}}}},[`&-prev-icon, + &-next-icon, + &-super-prev-icon, + &-super-next-icon`]:{position:"relative",display:"inline-block",width:i,height:i,"&::before":{position:"absolute",top:0,insetInlineStart:0,display:"inline-block",width:i,height:i,border:"0 solid currentcolor",borderBlockStartWidth:m,borderBlockEndWidth:0,borderInlineStartWidth:m,borderInlineEndWidth:0,content:'""'}},[`&-super-prev-icon, + &-super-next-icon`]:{"&::after":{position:"absolute",top:H,insetInlineStart:H,display:"inline-block",width:i,height:i,border:"0 solid currentcolor",borderBlockStartWidth:m,borderBlockEndWidth:0,borderInlineStartWidth:m,borderInlineEndWidth:0,content:'""'}},[`&-prev-icon, + &-super-prev-icon`]:{transform:"rotate(-45deg)"},[`&-next-icon, + &-super-next-icon`]:{transform:"rotate(135deg)"},"&-content":{width:"100%",tableLayout:"fixed",borderCollapse:"collapse","th, td":{position:"relative",minWidth:w,fontWeight:"normal"},th:{height:e.calc(w).add(e.calc(R).mul(2)).equal(),color:N,verticalAlign:"middle"}},"&-cell":Object.assign({padding:`${X(R)} 0`,color:P,cursor:"pointer","&-in-view":{color:N}},Zz(e)),[`&-decade-panel, + &-year-panel, + &-quarter-panel, + &-month-panel`]:{[`${t}-content`]:{height:e.calc(F).mul(4).equal()},[r]:{padding:`0 ${X(s)}`}},"&-quarter-panel":{[`${t}-content`]:{height:T}},"&-decade-panel":{[r]:{padding:`0 ${X(e.calc(s).div(2).equal())}`},[`${t}-cell::before`]:{display:"none"}},[`&-year-panel, + &-quarter-panel, + &-month-panel`]:{[`${t}-body`]:{padding:`0 ${X(s)}`},[r]:{width:o}},"&-date-panel":{[`${t}-body`]:{padding:`${X(s)} ${X(j)}`},[`${t}-content th`]:{boxSizing:"border-box",padding:0}},"&-week-panel":{[`${t}-cell`]:{[`&:hover ${r}, + &-selected ${r}, + ${r}`]:{background:"transparent !important"}},"&-row":{td:{"&:before":{transition:`background ${x}`},"&:first-child:before":{borderStartStartRadius:D,borderEndStartRadius:D},"&:last-child:before":{borderStartEndRadius:D,borderEndEndRadius:D}},["&:hover td"]:{"&:before":{background:O}},[`&-range-start td, + &-range-end td, + &-selected td`]:{[`&${n}`]:{"&:before":{background:g},[`&${t}-cell-week`]:{color:new Mt(_).setAlpha(.5).toHexString()},[r]:{color:_}}},["&-range-hover td:before"]:{background:B}}},["&-week-panel, &-date-panel-show-week"]:{[`${t}-body`]:{padding:`${X(s)} ${X(l)}`},[`${t}-content th`]:{width:"auto"}},"&-datetime-panel":{display:"flex",[`${t}-time-panel`]:{borderInlineStart:`${X(d)} ${v} ${b}`},[`${t}-date-panel, + ${t}-time-panel`]:{transition:`opacity ${z}`},"&-active":{[`${t}-date-panel, + ${t}-time-panel`]:{opacity:.3,"&-active":{opacity:1}}}},"&-time-panel":{width:"auto",minWidth:"auto",direction:"ltr",[`${t}-content`]:{display:"flex",flex:"auto",height:M},"&-column":{flex:"1 0 auto",width:L,margin:`${X(c)} 0`,padding:0,overflowY:"hidden",textAlign:"start",listStyle:"none",transition:`background ${x}`,overflowX:"hidden","&::-webkit-scrollbar":{width:8,backgroundColor:"transparent"},"&::-webkit-scrollbar-thumb":{backgroundColor:e.colorTextTertiary,borderRadius:4},"&":{scrollbarWidth:"thin",scrollbarColor:`${e.colorTextTertiary} transparent`},"&::after":{display:"block",height:e.calc("100%").sub(A).equal(),content:'""'},"&:not(:first-child)":{borderInlineStart:`${X(d)} ${v} ${b}`},"&-active":{background:new Mt(B).setAlpha(.2).toHexString()},"&:hover":{overflowY:"auto"},"> li":{margin:0,padding:0,[`&${t}-time-panel-cell`]:{marginInline:k,[`${t}-time-panel-cell-inner`]:{display:"block",width:e.calc(L).sub(e.calc(k).mul(2)).equal(),height:A,margin:0,paddingBlock:0,paddingInlineEnd:0,paddingInlineStart:e.calc(L).sub(A).div(2).equal(),color:N,lineHeight:X(A),borderRadius:D,cursor:"pointer",transition:`background ${x}`,"&:hover":{background:O}},"&-selected":{[`${t}-time-panel-cell-inner`]:{background:B}},"&-disabled":{[`${t}-time-panel-cell-inner`]:{color:P,background:"transparent",cursor:"not-allowed"}}}}}}}}},Jz=e=>{const{componentCls:t,textHeight:n,lineWidth:r,paddingSM:o,antCls:i,colorPrimary:a,cellActiveWithRangeBg:l,colorPrimaryBorder:s,lineType:c,colorSplit:u}=e;return{[`${t}-dropdown`]:{[`${t}-footer`]:{borderTop:`${X(r)} ${c} ${u}`,"&-extra":{padding:`0 ${X(o)}`,lineHeight:X(e.calc(n).sub(e.calc(r).mul(2)).equal()),textAlign:"start","&:not(:last-child)":{borderBottom:`${X(r)} ${c} ${u}`}}},[`${t}-panels + ${t}-footer ${t}-ranges`]:{justifyContent:"space-between"},[`${t}-ranges`]:{marginBlock:0,paddingInline:X(o),overflow:"hidden",textAlign:"start",listStyle:"none",display:"flex",justifyContent:"center",alignItems:"center","> li":{lineHeight:X(e.calc(n).sub(e.calc(r).mul(2)).equal()),display:"inline-block"},[`${t}-now-btn-disabled`]:{pointerEvents:"none",color:e.colorTextDisabled},[`${t}-preset > ${i}-tag-blue`]:{color:a,background:l,borderColor:s,cursor:"pointer"},[`${t}-ok`]:{paddingBlock:e.calc(r).mul(2).equal(),marginInlineStart:"auto"}}}}},eF=Jz,a$=e=>{const{componentCls:t,controlHeightLG:n,paddingXXS:r,padding:o}=e;return{pickerCellCls:`${t}-cell`,pickerCellInnerCls:`${t}-cell-inner`,pickerYearMonthCellWidth:e.calc(n).mul(1.5).equal(),pickerQuarterPanelContentHeight:e.calc(n).mul(1.4).equal(),pickerCellPaddingVertical:e.calc(r).add(e.calc(r).div(2)).equal(),pickerCellBorderGap:2,pickerControlIconSize:7,pickerControlIconMargin:4,pickerControlIconBorderWidth:1.5,pickerDatePanelPaddingHorizontal:e.calc(o).add(e.calc(r).div(2)).equal()}},l$=e=>{const{colorBgContainerDisabled:t,controlHeightSM:n,controlHeightLG:r}=e;return{cellHoverBg:e.controlItemBgHover,cellActiveWithRangeBg:e.controlItemBgActive,cellHoverWithRangeBg:new Mt(e.colorPrimary).lighten(35).toHexString(),cellRangeBorderColor:new Mt(e.colorPrimary).lighten(20).toHexString(),cellBgDisabled:t,timeColumnWidth:r*1.4,timeColumnHeight:28*8,timeCellHeight:28,cellWidth:n*1.5,cellHeight:n,textHeight:r,withoutTimeCellHeight:r*1.65,multipleItemBg:e.colorFillSecondary,multipleItemBorderColor:"transparent",multipleItemHeight:n,multipleItemHeightLG:e.controlHeight,multipleSelectorBgDisabled:t,multipleItemColorDisabled:e.colorTextDisabled,multipleItemBorderColorDisabled:"transparent"}},tF=e=>Object.assign(Object.assign(Object.assign(Object.assign({},q2(e)),l$(e)),hm(e)),{presetsWidth:120,presetsMaxWidth:200,zIndexPopup:e.zIndexPopupBase+50}),nF=e=>{const{componentCls:t}=e;return{[t]:[Object.assign(Object.assign(Object.assign({},Q2(e)),e$(e)),Z2(e)),{"&-outlined":{[`&${t}-multiple ${t}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}},"&-filled":{[`&${t}-multiple ${t}-selection-item`]:{background:e.colorBgContainer,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`}},"&-borderless":{[`&${t}-multiple ${t}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}}}]}},rF=nF,Sv=(e,t,n,r)=>{const o=e.calc(n).add(2).equal(),i=e.max(e.calc(t).sub(o).div(2).equal(),0),a=e.max(e.calc(t).sub(o).sub(i).equal(),0);return{padding:`${X(i)} ${X(r)} ${X(a)}`}},oF=e=>{const{componentCls:t,colorError:n,colorWarning:r}=e;return{[`${t}:not(${t}-disabled):not([disabled])`]:{[`&${t}-status-error`]:{[`${t}-active-bar`]:{background:n}},[`&${t}-status-warning`]:{[`${t}-active-bar`]:{background:r}}}}},iF=e=>{const{componentCls:t,antCls:n,controlHeight:r,paddingInline:o,lineWidth:i,lineType:a,colorBorder:l,borderRadius:s,motionDurationMid:c,colorTextDisabled:u,colorTextPlaceholder:d,controlHeightLG:v,fontSizeLG:h,controlHeightSM:g,paddingInlineSM:p,paddingXS:b,marginXS:m,colorTextDescription:y,lineWidthBold:S,colorPrimary:x,motionDurationSlow:$,zIndexPopup:E,paddingXXS:w,sizePopupArrow:R,colorBgElevated:P,borderRadiusLG:N,boxShadowSecondary:I,borderRadiusSM:z,colorSplit:F,cellHoverBg:T,presetsWidth:D,presetsMaxWidth:_,boxShadowPopoverArrow:O,fontHeight:M,fontHeightLG:L,lineHeightLG:A}=e;return[{[t]:Object.assign(Object.assign(Object.assign({},Qt(e)),Sv(e,r,M,o)),{position:"relative",display:"inline-flex",alignItems:"center",lineHeight:1,borderRadius:s,transition:`border ${c}, box-shadow ${c}, background ${c}`,[`${t}-input`]:{position:"relative",display:"inline-flex",alignItems:"center",width:"100%","> input":Object.assign(Object.assign({position:"relative",display:"inline-block",width:"100%",color:"inherit",fontSize:e.fontSize,lineHeight:e.lineHeight,transition:`all ${c}`},t$(d)),{flex:"auto",minWidth:1,height:"auto",padding:0,background:"transparent",border:0,fontFamily:"inherit","&:focus":{boxShadow:"none",outline:0},"&[disabled]":{background:"transparent",color:u,cursor:"not-allowed"}}),"&-placeholder":{"> input":{color:d}}},"&-large":Object.assign(Object.assign({},Sv(e,v,L,o)),{[`${t}-input > input`]:{fontSize:h,lineHeight:A}}),"&-small":Object.assign({},Sv(e,g,M,p)),[`${t}-suffix`]:{display:"flex",flex:"none",alignSelf:"center",marginInlineStart:e.calc(b).div(2).equal(),color:u,lineHeight:1,pointerEvents:"none",transition:`opacity ${c}, color ${c}`,"> *":{verticalAlign:"top","&:not(:last-child)":{marginInlineEnd:m}}},[`${t}-clear`]:{position:"absolute",top:"50%",insetInlineEnd:0,color:u,lineHeight:1,transform:"translateY(-50%)",cursor:"pointer",opacity:0,transition:`opacity ${c}, color ${c}`,"> *":{verticalAlign:"top"},"&:hover":{color:y}},"&:hover":{[`${t}-clear`]:{opacity:1},[`${t}-suffix:not(:last-child)`]:{opacity:0}},[`${t}-separator`]:{position:"relative",display:"inline-block",width:"1em",height:h,color:u,fontSize:h,verticalAlign:"top",cursor:"default",[`${t}-focused &`]:{color:y},[`${t}-range-separator &`]:{[`${t}-disabled &`]:{cursor:"not-allowed"}}},"&-range":{position:"relative",display:"inline-flex",[`${t}-active-bar`]:{bottom:e.calc(i).mul(-1).equal(),height:S,background:x,opacity:0,transition:`all ${$} ease-out`,pointerEvents:"none"},[`&${t}-focused`]:{[`${t}-active-bar`]:{opacity:1}},[`${t}-range-separator`]:{alignItems:"center",padding:`0 ${X(b)}`,lineHeight:1}},"&-range, &-multiple":{[`${t}-clear`]:{insetInlineEnd:o},[`&${t}-small`]:{[`${t}-clear`]:{insetInlineEnd:p}}},"&-dropdown":Object.assign(Object.assign(Object.assign({},Qt(e)),i$(e)),{pointerEvents:"none",position:"absolute",top:-9999,left:{_skip_check_:!0,value:-9999},zIndex:E,[`&${t}-dropdown-hidden`]:{display:"none"},[`&${t}-dropdown-placement-bottomLeft`]:{[`${t}-range-arrow`]:{top:0,display:"block",transform:"translateY(-100%)"}},[`&${t}-dropdown-placement-topLeft`]:{[`${t}-range-arrow`]:{bottom:0,display:"block",transform:"translateY(100%) rotate(180deg)"}},[`&${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-topLeft, + &${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-topRight, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-topLeft, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-topRight`]:{animationName:om},[`&${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-bottomLeft, + &${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-bottomRight, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-bottomLeft, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-bottomRight`]:{animationName:nm},[`&${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-topLeft, + &${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-topRight`]:{animationName:im},[`&${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-bottomLeft, + &${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-bottomRight`]:{animationName:rm},[`${t}-panel > ${t}-time-panel`]:{paddingTop:w},[`${t}-range-wrapper`]:{display:"flex",position:"relative"},[`${t}-range-arrow`]:Object.assign(Object.assign({position:"absolute",zIndex:1,display:"none",paddingInline:e.calc(o).mul(1.5).equal(),boxSizing:"content-box",transition:`left ${$} ease-out`},l2(e,P,O)),{"&:before":{insetInlineStart:e.calc(o).mul(1.5).equal()}}),[`${t}-panel-container`]:{overflow:"hidden",verticalAlign:"top",background:P,borderRadius:N,boxShadow:I,transition:`margin ${$}`,display:"inline-block",pointerEvents:"auto",[`${t}-panel-layout`]:{display:"flex",flexWrap:"nowrap",alignItems:"stretch"},[`${t}-presets`]:{display:"flex",flexDirection:"column",minWidth:D,maxWidth:_,ul:{height:0,flex:"auto",listStyle:"none",overflow:"auto",margin:0,padding:b,borderInlineEnd:`${X(i)} ${a} ${F}`,li:Object.assign(Object.assign({},ei),{borderRadius:z,paddingInline:b,paddingBlock:e.calc(g).sub(M).div(2).equal(),cursor:"pointer",transition:`all ${$}`,"+ li":{marginTop:m},"&:hover":{background:T}})}},[`${t}-panels`]:{display:"inline-flex",flexWrap:"nowrap",direction:"ltr","&:last-child":{[`${t}-panel`]:{borderWidth:0}}},[`${t}-panel`]:{verticalAlign:"top",background:"transparent",borderRadius:0,borderWidth:0,[`${t}-content, + table`]:{textAlign:"center"},"&-focused":{borderColor:l}}}}),"&-dropdown-range":{padding:`${X(e.calc(R).mul(2).div(3).equal())} 0`,"&-hidden":{display:"none"}},"&-rtl":{direction:"rtl",[`${t}-separator`]:{transform:"rotate(180deg)"},[`${t}-footer`]:{"&-extra":{direction:"rtl"}}}})},Xa(e,"slide-up"),Xa(e,"slide-down"),Zu(e,"move-up"),Zu(e,"move-down")]};vn("DatePicker",e=>{const t=$t(K2(e),a$(e),{inputPaddingHorizontalBase:e.calc(e.paddingSM).sub(1).equal(),multipleSelectItemHeight:e.multipleItemHeight,selectHeight:e.controlHeight});return[eF(t),iF(t),rF(t),oF(t),Qz(t),tf(e,{focusElCls:`${e.componentCls}-focused`})]},tF);const aF=e=>{const{calendarCls:t,componentCls:n,fullBg:r,fullPanelBg:o,itemActiveBg:i}=e;return{[t]:Object.assign(Object.assign(Object.assign({},i$(e)),Qt(e)),{background:r,"&-rtl":{direction:"rtl"},[`${t}-header`]:{display:"flex",justifyContent:"flex-end",padding:`${X(e.paddingSM)} 0`,[`${t}-year-select`]:{minWidth:e.yearControlWidth},[`${t}-month-select`]:{minWidth:e.monthControlWidth,marginInlineStart:e.marginXS},[`${t}-mode-switch`]:{marginInlineStart:e.marginXS}}}),[`${t} ${n}-panel`]:{background:o,border:0,borderTop:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`,borderRadius:0,[`${n}-month-panel, ${n}-date-panel`]:{width:"auto"},[`${n}-body`]:{padding:`${X(e.paddingXS)} 0`},[`${n}-content`]:{width:"100%"}},[`${t}-mini`]:{borderRadius:e.borderRadiusLG,[`${t}-header`]:{paddingInlineEnd:e.paddingXS,paddingInlineStart:e.paddingXS},[`${n}-panel`]:{borderRadius:`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},[`${n}-content`]:{height:e.miniContentHeight,th:{height:"auto",padding:0,lineHeight:`${X(e.weekHeight)}`}},[`${n}-cell::before`]:{pointerEvents:"none"}},[`${t}${t}-full`]:{[`${n}-panel`]:{display:"block",width:"100%",textAlign:"end",background:r,border:0,[`${n}-body`]:{"th, td":{padding:0},th:{height:"auto",paddingInlineEnd:e.paddingSM,paddingBottom:e.paddingXXS,lineHeight:`${X(e.weekHeight)}`}}},[`${n}-cell`]:{"&::before":{display:"none"},"&:hover":{[`${t}-date`]:{background:e.controlItemBgHover}},[`${t}-date-today::before`]:{display:"none"},[`&-in-view${n}-cell-selected`]:{[`${t}-date, ${t}-date-today`]:{background:i}},"&-selected, &-selected:hover":{[`${t}-date, ${t}-date-today`]:{[`${t}-date-value`]:{color:e.colorPrimary}}}},[`${t}-date`]:{display:"block",width:"auto",height:"auto",margin:`0 ${X(e.calc(e.marginXS).div(2).equal())}`,padding:`${X(e.calc(e.paddingXS).div(2).equal())} ${X(e.paddingXS)} 0`,border:0,borderTop:`${X(e.lineWidthBold)} ${e.lineType} ${e.colorSplit}`,borderRadius:0,transition:`background ${e.motionDurationSlow}`,"&-value":{lineHeight:`${X(e.dateValueHeight)}`,transition:`color ${e.motionDurationSlow}`},"&-content":{position:"static",width:"auto",height:e.dateContentHeight,overflowY:"auto",color:e.colorText,lineHeight:e.lineHeight,textAlign:"start"},"&-today":{borderColor:e.colorPrimary,[`${t}-date-value`]:{color:e.colorText}}}},[`@media only screen and (max-width: ${X(e.screenXS)}) `]:{[`${t}`]:{[`${t}-header`]:{display:"block",[`${t}-year-select`]:{width:"50%"},[`${t}-month-select`]:{width:`calc(50% - ${X(e.paddingXS)})`},[`${t}-mode-switch`]:{width:"100%",marginTop:e.marginXS,marginInlineStart:0,"> label":{width:"50%",textAlign:"center"}}}}}}},lF=e=>Object.assign({fullBg:e.colorBgContainer,fullPanelBg:e.colorBgContainer,itemActiveBg:e.controlItemBgActive,yearControlWidth:80,monthControlWidth:70,miniContentHeight:256},l$(e)),sF=vn("Calendar",e=>{const t=`${e.componentCls}-calendar`,n=$t(e,a$(e),{calendarCls:t,pickerCellInnerCls:`${e.componentCls}-cell-inner`,dateValueHeight:e.controlHeightSM,weekHeight:e.calc(e.controlHeightSM).mul(.75).equal(),dateContentHeight:e.calc(e.calc(e.fontHeightSM).add(e.marginXS)).mul(3).add(e.calc(e.lineWidth).mul(2)).equal()});return[aF(n)]},lF);function s$(e){function t(i,a){return i&&a&&e.getYear(i)===e.getYear(a)}function n(i,a){return t(i,a)&&e.getMonth(i)===e.getMonth(a)}function r(i,a){return n(i,a)&&e.getDate(i)===e.getDate(a)}return i=>{const{prefixCls:a,className:l,rootClassName:s,style:c,dateFullCellRender:u,dateCellRender:d,monthFullCellRender:v,monthCellRender:h,cellRender:g,fullCellRender:p,headerRender:b,value:m,defaultValue:y,disabledDate:S,mode:x,validRange:$,fullscreen:E=!0,onChange:w,onPanelChange:R,onSelect:P}=i,{getPrefixCls:N,direction:I,calendar:z}=f.exports.useContext(ot),F=N("picker",a),T=`${F}-calendar`,[D,_,O]=sF(F,T),M=e.getNow(),[L,A]=kt(()=>m||e.getNow(),{defaultValue:y,value:m}),[B,k]=kt("month",{value:x}),j=f.exports.useMemo(()=>B==="year"?"month":"date",[B]),H=f.exports.useCallback(J=>($?e.isAfter($[0],J)||e.isAfter(J,$[1]):!1)||!!(S!=null&&S(J)),[S,$]),W=(J,re)=>{R==null||R(J,re)},Y=J=>{A(J),r(J,L)||((j==="date"&&!n(J,L)||j==="month"&&!t(J,L))&&W(J,B),w==null||w(J))},K=J=>{k(J),W(L,J)},q=(J,re)=>{Y(J),P==null||P(J,{source:re})},ee=()=>{const{locale:J}=i,re=Object.assign(Object.assign({},Kp),J);return re.lang=Object.assign(Object.assign({},re.lang),(J||{}).lang),re},Z=f.exports.useCallback((J,re)=>p?p(J,re):u?u(J):ie("div",{className:te(`${F}-cell-inner`,`${T}-date`,{[`${T}-date-today`]:r(M,J)}),children:[C("div",{className:`${T}-date-value`,children:String(e.getDate(J)).padStart(2,"0")}),C("div",{className:`${T}-date-content`,children:g?g(J,re):d&&d(J)})]}),[u,d,g,p]),Q=f.exports.useCallback((J,re)=>{if(p)return p(J,re);if(v)return v(J);const fe=re.locale.shortMonths||e.locale.getShortMonths(re.locale.locale);return ie("div",{className:te(`${F}-cell-inner`,`${T}-date`,{[`${T}-date-today`]:n(M,J)}),children:[C("div",{className:`${T}-date-value`,children:fe[e.getMonth(J)]}),C("div",{className:`${T}-date-content`,children:g?g(J,re):h&&h(J)})]})},[v,h,g,p]),[ne]=Wx("Calendar",ee),ae=(J,re)=>{if(re.type==="date")return Z(J,re);if(re.type==="month")return Q(J,Object.assign(Object.assign({},re),{locale:ne==null?void 0:ne.lang}))};return D(ie("div",{className:te(T,{[`${T}-full`]:E,[`${T}-mini`]:!E,[`${T}-rtl`]:I==="rtl"},z==null?void 0:z.className,l,s,_,O),style:Object.assign(Object.assign({},z==null?void 0:z.style),c),children:[b?b({value:L,type:B,onChange:J=>{q(J,"customize")},onTypeChange:K}):C(Fz,{prefixCls:T,value:L,generateConfig:e,mode:B,fullscreen:E,locale:ne==null?void 0:ne.lang,validRange:$,onChange:q,onModeChange:K}),C(yz,{value:L,prefixCls:F,locale:ne==null?void 0:ne.lang,generateConfig:e,cellRender:ae,onSelect:J=>{q(J,j)},mode:j,picker:j,disabledDate:H,hideHeader:!0})]}))}}const c$=s$(VL);c$.generateCalendar=s$;const cF=c$,uF=e=>{const{prefixCls:t,className:n,style:r,size:o,shape:i}=e,a=te({[`${t}-lg`]:o==="large",[`${t}-sm`]:o==="small"}),l=te({[`${t}-circle`]:i==="circle",[`${t}-square`]:i==="square",[`${t}-round`]:i==="round"}),s=f.exports.useMemo(()=>typeof o=="number"?{width:o,height:o,lineHeight:`${o}px`}:{},[o]);return C("span",{className:te(t,a,l,n),style:Object.assign(Object.assign({},s),r)})},vf=uF,dF=new Ct("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),pf=e=>({height:e,lineHeight:X(e)}),Da=e=>Object.assign({width:e},pf(e)),fF=e=>({background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:dF,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"}),Cv=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},pf(e)),vF=e=>{const{skeletonAvatarCls:t,gradientFromColor:n,controlHeight:r,controlHeightLG:o,controlHeightSM:i}=e;return{[`${t}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:n},Da(r)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},Da(o)),[`${t}${t}-sm`]:Object.assign({},Da(i))}},pF=e=>{const{controlHeight:t,borderRadiusSM:n,skeletonInputCls:r,controlHeightLG:o,controlHeightSM:i,gradientFromColor:a,calc:l}=e;return{[`${r}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:a,borderRadius:n},Cv(t,l)),[`${r}-lg`]:Object.assign({},Cv(o,l)),[`${r}-sm`]:Object.assign({},Cv(i,l))}},qb=e=>Object.assign({width:e},pf(e)),gF=e=>{const{skeletonImageCls:t,imageSizeBase:n,gradientFromColor:r,borderRadiusSM:o,calc:i}=e;return{[`${t}`]:Object.assign(Object.assign({display:"flex",alignItems:"center",justifyContent:"center",verticalAlign:"top",background:r,borderRadius:o},qb(i(n).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},qb(n)),{maxWidth:i(n).mul(4).equal(),maxHeight:i(n).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}},xv=(e,t,n)=>{const{skeletonButtonCls:r}=e;return{[`${n}${r}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${n}${r}-round`]:{borderRadius:t}}},wv=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},pf(e)),hF=e=>{const{borderRadiusSM:t,skeletonButtonCls:n,controlHeight:r,controlHeightLG:o,controlHeightSM:i,gradientFromColor:a,calc:l}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[`${n}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:a,borderRadius:t,width:l(r).mul(2).equal(),minWidth:l(r).mul(2).equal()},wv(r,l))},xv(e,r,n)),{[`${n}-lg`]:Object.assign({},wv(o,l))}),xv(e,o,`${n}-lg`)),{[`${n}-sm`]:Object.assign({},wv(i,l))}),xv(e,i,`${n}-sm`))},mF=e=>{const{componentCls:t,skeletonAvatarCls:n,skeletonTitleCls:r,skeletonParagraphCls:o,skeletonButtonCls:i,skeletonInputCls:a,skeletonImageCls:l,controlHeight:s,controlHeightLG:c,controlHeightSM:u,gradientFromColor:d,padding:v,marginSM:h,borderRadius:g,titleHeight:p,blockRadius:b,paragraphLiHeight:m,controlHeightXS:y,paragraphMarginTop:S}=e;return{[`${t}`]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:v,verticalAlign:"top",[`${n}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:d},Da(s)),[`${n}-circle`]:{borderRadius:"50%"},[`${n}-lg`]:Object.assign({},Da(c)),[`${n}-sm`]:Object.assign({},Da(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[`${r}`]:{width:"100%",height:p,background:d,borderRadius:b,[`+ ${o}`]:{marginBlockStart:u}},[`${o}`]:{padding:0,"> li":{width:"100%",height:m,listStyle:"none",background:d,borderRadius:b,"+ li":{marginBlockStart:y}}},[`${o}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${r}, ${o} > li`]:{borderRadius:g}}},[`${t}-with-avatar ${t}-content`]:{[`${r}`]:{marginBlockStart:h,[`+ ${o}`]:{marginBlockStart:S}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},hF(e)),vF(e)),pF(e)),gF(e)),[`${t}${t}-block`]:{width:"100%",[`${i}`]:{width:"100%"},[`${a}`]:{width:"100%"}},[`${t}${t}-active`]:{[` + ${r}, + ${o} > li, + ${n}, + ${i}, + ${a}, + ${l} + `]:Object.assign({},fF(e))}}},yF=e=>{const{colorFillContent:t,colorFill:n}=e,r=t,o=n;return{color:r,colorGradientEnd:o,gradientFromColor:r,gradientToColor:o,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},ll=vn("Skeleton",e=>{const{componentCls:t,calc:n}=e,r=$t(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:n(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"});return[mF(r)]},yF,{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),bF=e=>{const{prefixCls:t,className:n,rootClassName:r,active:o,shape:i="circle",size:a="default"}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=lr(e,["prefixCls","className"]),h=te(s,`${s}-element`,{[`${s}-active`]:o},n,r,u,d);return c(C("div",{className:h,children:C(vf,{...Object.assign({prefixCls:`${s}-avatar`,shape:i,size:a},v)})}))},SF=bF,CF=e=>{const{prefixCls:t,className:n,rootClassName:r,active:o,block:i=!1,size:a="default"}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=lr(e,["prefixCls"]),h=te(s,`${s}-element`,{[`${s}-active`]:o,[`${s}-block`]:i},n,r,u,d);return c(C("div",{className:h,children:C(vf,{...Object.assign({prefixCls:`${s}-button`,size:a},v)})}))},xF=CF,wF="M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",$F=e=>{const{prefixCls:t,className:n,rootClassName:r,style:o,active:i}=e,{getPrefixCls:a}=f.exports.useContext(ot),l=a("skeleton",t),[s,c,u]=ll(l),d=te(l,`${l}-element`,{[`${l}-active`]:i},n,r,c,u);return s(C("div",{className:d,children:C("div",{className:te(`${l}-image`,n),style:o,children:C("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${l}-image-svg`,children:C("path",{d:wF,className:`${l}-image-path`})})})}))},EF=$F,MF=e=>{const{prefixCls:t,className:n,rootClassName:r,active:o,block:i,size:a="default"}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=lr(e,["prefixCls"]),h=te(s,`${s}-element`,{[`${s}-active`]:o,[`${s}-block`]:i},n,r,u,d);return c(C("div",{className:h,children:C(vf,{...Object.assign({prefixCls:`${s}-input`,size:a},v)})}))},OF=MF,RF=e=>{const{prefixCls:t,className:n,rootClassName:r,style:o,active:i,children:a}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=te(s,`${s}-element`,{[`${s}-active`]:i},u,n,r,d),h=a!=null?a:C(UI,{});return c(C("div",{className:v,children:C("div",{className:te(`${s}-image`,n),style:o,children:h})}))},IF=RF,PF=e=>{const t=l=>{const{width:s,rows:c=2}=e;if(Array.isArray(s))return s[l];if(c-1===l)return s},{prefixCls:n,className:r,style:o,rows:i}=e,a=Oe(Array(i)).map((l,s)=>C("li",{style:{width:t(s)}},s));return C("ul",{className:te(n,r),style:o,children:a})},TF=PF,NF=e=>{let{prefixCls:t,className:n,width:r,style:o}=e;return C("h3",{className:te(t,n),style:Object.assign({width:r},o)})},_F=NF;function $v(e){return e&&typeof e=="object"?e:{}}function AF(e,t){return e&&!t?{size:"large",shape:"square"}:{size:"large",shape:"circle"}}function DF(e,t){return!e&&t?{width:"38%"}:e&&t?{width:"50%"}:{}}function LF(e,t){const n={};return(!e||!t)&&(n.width="61%"),!e&&t?n.rows=3:n.rows=2,n}const sl=e=>{const{prefixCls:t,loading:n,className:r,rootClassName:o,style:i,children:a,avatar:l=!1,title:s=!0,paragraph:c=!0,active:u,round:d}=e,{getPrefixCls:v,direction:h,skeleton:g}=f.exports.useContext(ot),p=v("skeleton",t),[b,m,y]=ll(p);if(n||!("loading"in e)){const S=!!l,x=!!s,$=!!c;let E;if(S){const P=Object.assign(Object.assign({prefixCls:`${p}-avatar`},AF(x,$)),$v(l));E=C("div",{className:`${p}-header`,children:C(vf,{...Object.assign({},P)})})}let w;if(x||$){let P;if(x){const I=Object.assign(Object.assign({prefixCls:`${p}-title`},DF(S,$)),$v(s));P=C(_F,{...Object.assign({},I)})}let N;if($){const I=Object.assign(Object.assign({prefixCls:`${p}-paragraph`},LF(S,x)),$v(c));N=C(TF,{...Object.assign({},I)})}w=ie("div",{className:`${p}-content`,children:[P,N]})}const R=te(p,{[`${p}-with-avatar`]:S,[`${p}-active`]:u,[`${p}-rtl`]:h==="rtl",[`${p}-round`]:d},g==null?void 0:g.className,r,o,m,y);return b(ie("div",{className:R,style:Object.assign(Object.assign({},g==null?void 0:g.style),i),children:[E,w]}))}return typeof a<"u"?a:null};sl.Button=xF;sl.Avatar=SF;sl.Input=OF;sl.Image=EF;sl.Node=IF;const zF=sl,gf=f.exports.createContext(null);var FF=function(t){var n=t.activeTabOffset,r=t.horizontal,o=t.rtl,i=t.indicator,a=i===void 0?{}:i,l=a.size,s=a.align,c=s===void 0?"center":s,u=f.exports.useState(),d=G(u,2),v=d[0],h=d[1],g=f.exports.useRef(),p=lt.useCallback(function(m){return typeof l=="function"?l(m):typeof l=="number"?l:m},[l]);function b(){St.cancel(g.current)}return f.exports.useEffect(function(){var m={};if(n)if(r){m.width=p(n.width);var y=o?"right":"left";c==="start"&&(m[y]=n[y]),c==="center"&&(m[y]=n[y]+n.width/2,m.transform=o?"translateX(50%)":"translateX(-50%)"),c==="end"&&(m[y]=n[y]+n.width,m.transform="translateX(-100%)")}else m.height=p(n.height),c==="start"&&(m.top=n.top),c==="center"&&(m.top=n.top+n.height/2,m.transform="translateY(-50%)"),c==="end"&&(m.top=n.top+n.height,m.transform="translateY(-100%)");return b(),g.current=St(function(){h(m)}),b},[n,r,o,c,p]),{style:v}},Xb={width:0,height:0,left:0,top:0};function kF(e,t,n){return f.exports.useMemo(function(){for(var r,o=new Map,i=t.get((r=e[0])===null||r===void 0?void 0:r.key)||Xb,a=i.left+i.width,l=0;lT?(z=N,E.current="x"):(z=I,E.current="y"),t(-z,-z)&&P.preventDefault()}var R=f.exports.useRef(null);R.current={onTouchStart:S,onTouchMove:x,onTouchEnd:$,onWheel:w},f.exports.useEffect(function(){function P(F){R.current.onTouchStart(F)}function N(F){R.current.onTouchMove(F)}function I(F){R.current.onTouchEnd(F)}function z(F){R.current.onWheel(F)}return document.addEventListener("touchmove",N,{passive:!1}),document.addEventListener("touchend",I,{passive:!1}),e.current.addEventListener("touchstart",P,{passive:!1}),e.current.addEventListener("wheel",z),function(){document.removeEventListener("touchmove",N),document.removeEventListener("touchend",I)}},[])}function u$(e){var t=f.exports.useState(0),n=G(t,2),r=n[0],o=n[1],i=f.exports.useRef(0),a=f.exports.useRef();return a.current=e,Hp(function(){var l;(l=a.current)===null||l===void 0||l.call(a)},[r]),function(){i.current===r&&(i.current+=1,o(i.current))}}function HF(e){var t=f.exports.useRef([]),n=f.exports.useState({}),r=G(n,2),o=r[1],i=f.exports.useRef(typeof e=="function"?e():e),a=u$(function(){var s=i.current;t.current.forEach(function(c){s=c(s)}),t.current=[],i.current=s,o({})});function l(s){t.current.push(s),a()}return[i.current,l]}var e1={width:0,height:0,left:0,top:0,right:0};function WF(e,t,n,r,o,i,a){var l=a.tabs,s=a.tabPosition,c=a.rtl,u,d,v;return["top","bottom"].includes(s)?(u="width",d=c?"right":"left",v=Math.abs(n)):(u="height",d="top",v=-n),f.exports.useMemo(function(){if(!l.length)return[0,0];for(var h=l.length,g=h,p=0;pv+t){g=p-1;break}}for(var m=0,y=h-1;y>=0;y-=1){var S=e.get(l[y].key)||e1;if(S[d]=g?[0,0]:[m,g]},[e,t,r,o,i,v,s,l.map(function(h){return h.key}).join("_"),c])}function t1(e){var t;return e instanceof Map?(t={},e.forEach(function(n,r){t[r]=n})):t=e,JSON.stringify(t)}var VF="TABS_DQ";function d$(e){return String(e).replace(/"/g,VF)}function f$(e,t,n,r){return!(!n||r||e===!1||e===void 0&&(t===!1||t===null))}var v$=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.editable,o=e.locale,i=e.style;return!r||r.showAdd===!1?null:C("button",{ref:t,type:"button",className:"".concat(n,"-nav-add"),style:i,"aria-label":(o==null?void 0:o.addAriaLabel)||"Add tab",onClick:function(l){r.onEdit("add",{event:l})},children:r.addIcon||"+"})}),n1=f.exports.forwardRef(function(e,t){var n=e.position,r=e.prefixCls,o=e.extra;if(!o)return null;var i,a={};return Qe(o)==="object"&&!f.exports.isValidElement(o)?a=o:a.right=o,n==="right"&&(i=a.right),n==="left"&&(i=a.left),i?C("div",{className:"".concat(r,"-extra-content"),ref:t,children:i}):null}),UF=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.id,o=e.tabs,i=e.locale,a=e.mobile,l=e.moreIcon,s=l===void 0?"More":l,c=e.moreTransitionName,u=e.style,d=e.className,v=e.editable,h=e.tabBarGutter,g=e.rtl,p=e.removeAriaLabel,b=e.onTabClick,m=e.getPopupContainer,y=e.popupClassName,S=f.exports.useState(!1),x=G(S,2),$=x[0],E=x[1],w=f.exports.useState(null),R=G(w,2),P=R[0],N=R[1],I="".concat(r,"-more-popup"),z="".concat(n,"-dropdown"),F=P!==null?"".concat(I,"-").concat(P):null,T=i==null?void 0:i.dropdownAriaLabel;function D(k,j){k.preventDefault(),k.stopPropagation(),v.onEdit("remove",{key:j,event:k})}var _=C(Qs,{onClick:function(j){var H=j.key,W=j.domEvent;b(H,W),E(!1)},prefixCls:"".concat(z,"-menu"),id:I,tabIndex:-1,role:"listbox","aria-activedescendant":F,selectedKeys:[P],"aria-label":T!==void 0?T:"expanded dropdown",children:o.map(function(k){var j=k.closable,H=k.disabled,W=k.closeIcon,Y=k.key,K=k.label,q=f$(j,W,v,H);return ie(cf,{id:"".concat(I,"-").concat(Y),role:"option","aria-controls":r&&"".concat(r,"-panel-").concat(Y),disabled:H,children:[C("span",{children:K}),q&&C("button",{type:"button","aria-label":p||"remove",tabIndex:0,className:"".concat(z,"-menu-item-remove"),onClick:function(Z){Z.stopPropagation(),D(Z,Y)},children:W||v.removeIcon||"\xD7"})]},Y)})});function O(k){for(var j=o.filter(function(q){return!q.disabled}),H=j.findIndex(function(q){return q.key===P})||0,W=j.length,Y=0;YVe?"left":"right"})}),F=G(z,2),T=F[0],D=F[1],_=Qb(0,function(We,Ve){!I&&p&&p({direction:We>Ve?"top":"bottom"})}),O=G(_,2),M=O[0],L=O[1],A=f.exports.useState([0,0]),B=G(A,2),k=B[0],j=B[1],H=f.exports.useState([0,0]),W=G(H,2),Y=W[0],K=W[1],q=f.exports.useState([0,0]),ee=G(q,2),Z=ee[0],Q=ee[1],ne=f.exports.useState([0,0]),ae=G(ne,2),J=ae[0],re=ae[1],fe=HF(new Map),ve=G(fe,2),pe=ve[0],oe=ve[1],se=kF(S,pe,Y[0]),le=Fc(k,I),Ce=Fc(Y,I),ce=Fc(Z,I),de=Fc(J,I),xe=lege?ge:We}var Se=f.exports.useRef(null),st=f.exports.useState(),nt=G(st,2),Ne=nt[0],Ee=nt[1];function _e(){Ee(Date.now())}function Be(){Se.current&&clearTimeout(Se.current)}jF(w,function(We,Ve){function vt(Ie,ze){Ie(function(Ke){var at=Pe(Ke+ze);return at})}return xe?(I?vt(D,We):vt(L,Ve),Be(),_e(),!0):!1}),f.exports.useEffect(function(){return Be(),Ne&&(Se.current=setTimeout(function(){Ee(0)},100)),Be},[Ne]);var qe=WF(se,he,I?T:M,Ce,ce,de,U(U({},e),{},{tabs:S})),it=G(qe,2),ft=it[0],ut=it[1],Ue=hn(function(){var We=arguments.length>0&&arguments[0]!==void 0?arguments[0]:a,Ve=se.get(We)||{width:0,height:0,left:0,right:0,top:0};if(I){var vt=T;l?Ve.rightT+he&&(vt=Ve.right+Ve.width-he):Ve.left<-T?vt=-Ve.left:Ve.left+Ve.width>-T+he&&(vt=-(Ve.left+Ve.width-he)),L(0),D(Pe(vt))}else{var Ie=M;Ve.top<-M?Ie=-Ve.top:Ve.top+Ve.height>-M+he&&(Ie=-(Ve.top+Ve.height-he)),D(0),L(Pe(Ie))}}),He={};d==="top"||d==="bottom"?He[l?"marginRight":"marginLeft"]=v:He.marginTop=v;var Xe=S.map(function(We,Ve){var vt=We.key;return C(GF,{id:o,prefixCls:y,tab:We,style:Ve===0?void 0:He,closable:We.closable,editable:c,active:vt===a,renderWrapper:h,removeAriaLabel:u==null?void 0:u.removeAriaLabel,onClick:function(ze){g(vt,ze)},onFocus:function(){Ue(vt),_e(),w.current&&(l||(w.current.scrollLeft=0),w.current.scrollTop=0)}},vt)}),Le=function(){return oe(function(){var Ve,vt=new Map,Ie=(Ve=R.current)===null||Ve===void 0?void 0:Ve.getBoundingClientRect();return S.forEach(function(ze){var Ke,at=ze.key,Gt=(Ke=R.current)===null||Ke===void 0?void 0:Ke.querySelector('[data-node-key="'.concat(d$(at),'"]'));if(Gt){var At=KF(Gt,Ie),Zt=G(At,4),Jt=Zt[0],kn=Zt[1],qn=Zt[2],pn=Zt[3];vt.set(at,{width:Jt,height:kn,left:qn,top:pn})}}),vt})};f.exports.useEffect(function(){Le()},[S.map(function(We){return We.key}).join("_")]);var Re=u$(function(){var We=ra(x),Ve=ra($),vt=ra(E);j([We[0]-Ve[0]-vt[0],We[1]-Ve[1]-vt[1]]);var Ie=ra(N);Q(Ie);var ze=ra(P);re(ze);var Ke=ra(R);K([Ke[0]-Ie[0],Ke[1]-Ie[1]]),Le()}),be=S.slice(0,ft),Ae=S.slice(ut+1),Me=[].concat(Oe(be),Oe(Ae)),$e=se.get(a),Te=FF({activeTabOffset:$e,horizontal:I,indicator:b,rtl:l}),ye=Te.style;f.exports.useEffect(function(){Ue()},[a,we,ge,t1($e),t1(se),I]),f.exports.useEffect(function(){Re()},[l]);var Ge=!!Me.length,Ze="".concat(y,"-nav-wrap"),et,ht,mt,ct;return I?l?(ht=T>0,et=T!==ge):(et=T<0,ht=T!==we):(mt=M<0,ct=M!==we),C(mr,{onResize:Re,children:ie("div",{ref:Fi(t,x),role:"tablist",className:te("".concat(y,"-nav"),n),style:r,onKeyDown:function(){_e()},children:[C(n1,{ref:$,position:"left",extra:s,prefixCls:y}),C(mr,{onResize:Re,children:C("div",{className:te(Ze,V(V(V(V({},"".concat(Ze,"-ping-left"),et),"".concat(Ze,"-ping-right"),ht),"".concat(Ze,"-ping-top"),mt),"".concat(Ze,"-ping-bottom"),ct)),ref:w,children:C(mr,{onResize:Re,children:ie("div",{ref:R,className:"".concat(y,"-nav-list"),style:{transform:"translate(".concat(T,"px, ").concat(M,"px)"),transition:Ne?"none":void 0},children:[Xe,C(v$,{ref:N,prefixCls:y,locale:u,editable:c,style:U(U({},Xe.length===0?void 0:He),{},{visibility:Ge?"hidden":null})}),C("div",{className:te("".concat(y,"-ink-bar"),V({},"".concat(y,"-ink-bar-animated"),i.inkBar)),style:ye})]})})})}),C(YF,{...e,removeAriaLabel:u==null?void 0:u.removeAriaLabel,ref:P,prefixCls:y,tabs:Me,className:!Ge&&ke,tabMoving:!!Ne}),C(n1,{ref:E,position:"right",extra:s,prefixCls:y})]})})}),p$=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.className,o=e.style,i=e.id,a=e.active,l=e.tabKey,s=e.children;return C("div",{id:i&&"".concat(i,"-panel-").concat(l),role:"tabpanel",tabIndex:a?0:-1,"aria-labelledby":i&&"".concat(i,"-tab-").concat(l),"aria-hidden":!a,style:o,className:te(n,a&&"".concat(n,"-active"),r),ref:t,children:s})}),qF=["renderTabBar"],XF=["label","key"],QF=function(t){var n=t.renderTabBar,r=Je(t,qF),o=f.exports.useContext(gf),i=o.tabs;if(n){var a=U(U({},r),{},{panes:i.map(function(l){var s=l.label,c=l.key,u=Je(l,XF);return C(p$,{tab:s,tabKey:c,...u},c)})});return n(a,r1)}return C(r1,{...r})},ZF=["key","forceRender","style","className","destroyInactiveTabPane"],JF=function(t){var n=t.id,r=t.activeKey,o=t.animated,i=t.tabPosition,a=t.destroyInactiveTabPane,l=f.exports.useContext(gf),s=l.prefixCls,c=l.tabs,u=o.tabPane,d="".concat(s,"-tabpane");return C("div",{className:te("".concat(s,"-content-holder")),children:C("div",{className:te("".concat(s,"-content"),"".concat(s,"-content-").concat(i),V({},"".concat(s,"-content-animated"),u)),children:c.map(function(v){var h=v.key,g=v.forceRender,p=v.style,b=v.className,m=v.destroyInactiveTabPane,y=Je(v,ZF),S=h===r;return C(to,{visible:S,forceRender:g,removeOnLeave:!!(a||m),leavedClassName:"".concat(d,"-hidden"),...o.tabPaneMotion,children:function(x,$){var E=x.style,w=x.className;return C(p$,{...y,prefixCls:d,id:n,tabKey:h,animated:u,active:S,style:U(U({},p),E),className:te(b,w),ref:$})}},h)})})})};function ek(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{inkBar:!0,tabPane:!1},t;return e===!1?t={inkBar:!1,tabPane:!1}:e===!0?t={inkBar:!0,tabPane:!1}:t=U({inkBar:!0},Qe(e)==="object"?e:{}),t.tabPaneMotion&&t.tabPane===void 0&&(t.tabPane=!0),!t.tabPaneMotion&&t.tabPane&&(t.tabPane=!1),t}var tk=["id","prefixCls","className","items","direction","activeKey","defaultActiveKey","editable","animated","tabPosition","tabBarGutter","tabBarStyle","tabBarExtraContent","locale","moreIcon","moreTransitionName","destroyInactiveTabPane","renderTabBar","onChange","onTabClick","onTabScroll","getPopupContainer","popupClassName","indicator"],o1=0,nk=f.exports.forwardRef(function(e,t){var n=e.id,r=e.prefixCls,o=r===void 0?"rc-tabs":r,i=e.className,a=e.items,l=e.direction,s=e.activeKey,c=e.defaultActiveKey,u=e.editable,d=e.animated,v=e.tabPosition,h=v===void 0?"top":v,g=e.tabBarGutter,p=e.tabBarStyle,b=e.tabBarExtraContent,m=e.locale,y=e.moreIcon,S=e.moreTransitionName,x=e.destroyInactiveTabPane,$=e.renderTabBar,E=e.onChange,w=e.onTabClick,R=e.onTabScroll,P=e.getPopupContainer,N=e.popupClassName,I=e.indicator,z=Je(e,tk),F=f.exports.useMemo(function(){return(a||[]).filter(function(re){return re&&Qe(re)==="object"&&"key"in re})},[a]),T=l==="rtl",D=ek(d),_=f.exports.useState(!1),O=G(_,2),M=O[0],L=O[1];f.exports.useEffect(function(){L(am())},[]);var A=kt(function(){var re;return(re=F[0])===null||re===void 0?void 0:re.key},{value:s,defaultValue:c}),B=G(A,2),k=B[0],j=B[1],H=f.exports.useState(function(){return F.findIndex(function(re){return re.key===k})}),W=G(H,2),Y=W[0],K=W[1];f.exports.useEffect(function(){var re=F.findIndex(function(ve){return ve.key===k});if(re===-1){var fe;re=Math.max(0,Math.min(Y,F.length-1)),j((fe=F[re])===null||fe===void 0?void 0:fe.key)}K(re)},[F.map(function(re){return re.key}).join("_"),k,Y]);var q=kt(null,{value:n}),ee=G(q,2),Z=ee[0],Q=ee[1];f.exports.useEffect(function(){n||(Q("rc-tabs-".concat(o1)),o1+=1)},[]);function ne(re,fe){w==null||w(re,fe);var ve=re!==k;j(re),ve&&(E==null||E(re))}var ae={id:Z,activeKey:k,animated:D,tabPosition:h,rtl:T,mobile:M},J=U(U({},ae),{},{editable:u,locale:m,moreIcon:y,moreTransitionName:S,tabBarGutter:g,onTabClick:ne,onTabScroll:R,extra:b,style:p,panes:null,getPopupContainer:P,popupClassName:N,indicator:I});return C(gf.Provider,{value:{tabs:F,prefixCls:o},children:ie("div",{ref:t,id:n,className:te(o,"".concat(o,"-").concat(h),V(V(V({},"".concat(o,"-mobile"),M),"".concat(o,"-editable"),u),"".concat(o,"-rtl"),T),i),...z,children:[C(QF,{...J,renderTabBar:$}),C(JF,{destroyInactiveTabPane:x,...ae,animated:D})]})})});const rk={motionAppear:!1,motionEnter:!0,motionLeave:!0};function ok(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{inkBar:!0,tabPane:!1},n;return t===!1?n={inkBar:!1,tabPane:!1}:t===!0?n={inkBar:!0,tabPane:!0}:n=Object.assign({inkBar:!0},typeof t=="object"?t:{}),n.tabPane&&(n.tabPaneMotion=Object.assign(Object.assign({},rk),{motionName:ni(e,"switch")})),n}var ik=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);ot)}function lk(e,t){if(e)return e;const n=Qo(t).map(r=>{if(f.exports.isValidElement(r)){const{key:o,props:i}=r,a=i||{},{tab:l}=a,s=ik(a,["tab"]);return Object.assign(Object.assign({key:String(o)},s),{label:l})}return null});return ak(n)}const sk=e=>{const{componentCls:t,motionDurationSlow:n}=e;return[{[t]:{[`${t}-switch`]:{"&-appear, &-enter":{transition:"none","&-start":{opacity:0},"&-active":{opacity:1,transition:`opacity ${n}`}},"&-leave":{position:"absolute",transition:"none",inset:0,"&-start":{opacity:1},"&-active":{opacity:0,transition:`opacity ${n}`}}}}},[Xa(e,"slide-up"),Xa(e,"slide-down")]]},ck=sk,uk=e=>{const{componentCls:t,tabsCardPadding:n,cardBg:r,cardGutter:o,colorBorderSecondary:i,itemSelectedColor:a}=e;return{[`${t}-card`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{margin:0,padding:n,background:r,border:`${X(e.lineWidth)} ${e.lineType} ${i}`,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOut}`},[`${t}-tab-active`]:{color:a,background:e.colorBgContainer},[`${t}-ink-bar`]:{visibility:"hidden"}},[`&${t}-top, &${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab + ${t}-tab`]:{marginLeft:{_skip_check_:!0,value:X(o)}}}},[`&${t}-top`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`},[`${t}-tab-active`]:{borderBottomColor:e.colorBgContainer}}},[`&${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},[`${t}-tab-active`]:{borderTopColor:e.colorBgContainer}}},[`&${t}-left, &${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab + ${t}-tab`]:{marginTop:X(o)}}},[`&${t}-left`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`${X(e.borderRadiusLG)} 0 0 ${X(e.borderRadiusLG)}`}},[`${t}-tab-active`]:{borderRightColor:{_skip_check_:!0,value:e.colorBgContainer}}}},[`&${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0`}},[`${t}-tab-active`]:{borderLeftColor:{_skip_check_:!0,value:e.colorBgContainer}}}}}}},dk=e=>{const{componentCls:t,itemHoverColor:n,dropdownEdgeChildVerticalPadding:r}=e;return{[`${t}-dropdown`]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",top:-9999,left:{_skip_check_:!0,value:-9999},zIndex:e.zIndexPopup,display:"block","&-hidden":{display:"none"},[`${t}-dropdown-menu`]:{maxHeight:e.tabsDropdownHeight,margin:0,padding:`${X(r)} 0`,overflowX:"hidden",overflowY:"auto",textAlign:{_skip_check_:!0,value:"left"},listStyleType:"none",backgroundColor:e.colorBgContainer,backgroundClip:"padding-box",borderRadius:e.borderRadiusLG,outline:"none",boxShadow:e.boxShadowSecondary,"&-item":Object.assign(Object.assign({},ei),{display:"flex",alignItems:"center",minWidth:e.tabsDropdownWidth,margin:0,padding:`${X(e.paddingXXS)} ${X(e.paddingSM)}`,color:e.colorText,fontWeight:"normal",fontSize:e.fontSize,lineHeight:e.lineHeight,cursor:"pointer",transition:`all ${e.motionDurationSlow}`,"> span":{flex:1,whiteSpace:"nowrap"},"&-remove":{flex:"none",marginLeft:{_skip_check_:!0,value:e.marginSM},color:e.colorTextDescription,fontSize:e.fontSizeSM,background:"transparent",border:0,cursor:"pointer","&:hover":{color:n}},"&:hover":{background:e.controlItemBgHover},"&-disabled":{"&, &:hover":{color:e.colorTextDisabled,background:"transparent",cursor:"not-allowed"}}})}})}},fk=e=>{const{componentCls:t,margin:n,colorBorderSecondary:r,horizontalMargin:o,verticalItemPadding:i,verticalItemMargin:a,calc:l}=e;return{[`${t}-top, ${t}-bottom`]:{flexDirection:"column",[`> ${t}-nav, > div > ${t}-nav`]:{margin:o,"&::before":{position:"absolute",right:{_skip_check_:!0,value:0},left:{_skip_check_:!0,value:0},borderBottom:`${X(e.lineWidth)} ${e.lineType} ${r}`,content:"''"},[`${t}-ink-bar`]:{height:e.lineWidthBold,"&-animated":{transition:`width ${e.motionDurationSlow}, left ${e.motionDurationSlow}, + right ${e.motionDurationSlow}`}},[`${t}-nav-wrap`]:{"&::before, &::after":{top:0,bottom:0,width:e.controlHeight},"&::before":{left:{_skip_check_:!0,value:0},boxShadow:e.boxShadowTabsOverflowLeft},"&::after":{right:{_skip_check_:!0,value:0},boxShadow:e.boxShadowTabsOverflowRight},[`&${t}-nav-wrap-ping-left::before`]:{opacity:1},[`&${t}-nav-wrap-ping-right::after`]:{opacity:1}}}},[`${t}-top`]:{[`> ${t}-nav, + > div > ${t}-nav`]:{"&::before":{bottom:0},[`${t}-ink-bar`]:{bottom:0}}},[`${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{order:1,marginTop:n,marginBottom:0,"&::before":{top:0},[`${t}-ink-bar`]:{top:0}},[`> ${t}-content-holder, > div > ${t}-content-holder`]:{order:0}},[`${t}-left, ${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{flexDirection:"column",minWidth:l(e.controlHeight).mul(1.25).equal(),[`${t}-tab`]:{padding:i,textAlign:"center"},[`${t}-tab + ${t}-tab`]:{margin:a},[`${t}-nav-wrap`]:{flexDirection:"column","&::before, &::after":{right:{_skip_check_:!0,value:0},left:{_skip_check_:!0,value:0},height:e.controlHeight},"&::before":{top:0,boxShadow:e.boxShadowTabsOverflowTop},"&::after":{bottom:0,boxShadow:e.boxShadowTabsOverflowBottom},[`&${t}-nav-wrap-ping-top::before`]:{opacity:1},[`&${t}-nav-wrap-ping-bottom::after`]:{opacity:1}},[`${t}-ink-bar`]:{width:e.lineWidthBold,"&-animated":{transition:`height ${e.motionDurationSlow}, top ${e.motionDurationSlow}`}},[`${t}-nav-list, ${t}-nav-operations`]:{flex:"1 0 auto",flexDirection:"column"}}},[`${t}-left`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-ink-bar`]:{right:{_skip_check_:!0,value:0}}},[`> ${t}-content-holder, > div > ${t}-content-holder`]:{marginLeft:{_skip_check_:!0,value:X(l(e.lineWidth).mul(-1).equal())},borderLeft:{_skip_check_:!0,value:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},[`> ${t}-content > ${t}-tabpane`]:{paddingLeft:{_skip_check_:!0,value:e.paddingLG}}}},[`${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{order:1,[`${t}-ink-bar`]:{left:{_skip_check_:!0,value:0}}},[`> ${t}-content-holder, > div > ${t}-content-holder`]:{order:0,marginRight:{_skip_check_:!0,value:l(e.lineWidth).mul(-1).equal()},borderRight:{_skip_check_:!0,value:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},[`> ${t}-content > ${t}-tabpane`]:{paddingRight:{_skip_check_:!0,value:e.paddingLG}}}}}},vk=e=>{const{componentCls:t,cardPaddingSM:n,cardPaddingLG:r,horizontalItemPaddingSM:o,horizontalItemPaddingLG:i}=e;return{[t]:{"&-small":{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:o,fontSize:e.titleFontSizeSM}}},"&-large":{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:i,fontSize:e.titleFontSizeLG}}}},[`${t}-card`]:{[`&${t}-small`]:{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:n}},[`&${t}-bottom`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:`0 0 ${X(e.borderRadius)} ${X(e.borderRadius)}`}},[`&${t}-top`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:`${X(e.borderRadius)} ${X(e.borderRadius)} 0 0`}},[`&${t}-right`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`0 ${X(e.borderRadius)} ${X(e.borderRadius)} 0`}}},[`&${t}-left`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`${X(e.borderRadius)} 0 0 ${X(e.borderRadius)}`}}}},[`&${t}-large`]:{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:r}}}}}},pk=e=>{const{componentCls:t,itemActiveColor:n,itemHoverColor:r,iconCls:o,tabsHorizontalItemMargin:i,horizontalItemPadding:a,itemSelectedColor:l,itemColor:s}=e,c=`${t}-tab`;return{[c]:{position:"relative",WebkitTouchCallout:"none",WebkitTapHighlightColor:"transparent",display:"inline-flex",alignItems:"center",padding:a,fontSize:e.titleFontSize,background:"transparent",border:0,outline:"none",cursor:"pointer",color:s,"&-btn, &-remove":Object.assign({"&:focus:not(:focus-visible), &:active":{color:n}},Xd(e)),"&-btn":{outline:"none",transition:"all 0.3s",[`${c}-icon:not(:last-child)`]:{marginInlineEnd:e.marginSM}},"&-remove":{flex:"none",marginRight:{_skip_check_:!0,value:e.calc(e.marginXXS).mul(-1).equal()},marginLeft:{_skip_check_:!0,value:e.marginXS},color:e.colorTextDescription,fontSize:e.fontSizeSM,background:"transparent",border:"none",outline:"none",cursor:"pointer",transition:`all ${e.motionDurationSlow}`,"&:hover":{color:e.colorTextHeading}},"&:hover":{color:r},[`&${c}-active ${c}-btn`]:{color:l,textShadow:e.tabsActiveTextShadow},[`&${c}-disabled`]:{color:e.colorTextDisabled,cursor:"not-allowed"},[`&${c}-disabled ${c}-btn, &${c}-disabled ${t}-remove`]:{"&:focus, &:active":{color:e.colorTextDisabled}},[`& ${c}-remove ${o}`]:{margin:0},[`${o}:not(:last-child)`]:{marginRight:{_skip_check_:!0,value:e.marginSM}}},[`${c} + ${c}`]:{margin:{_skip_check_:!0,value:i}}}},gk=e=>{const{componentCls:t,tabsHorizontalItemMarginRTL:n,iconCls:r,cardGutter:o,calc:i}=e;return{[`${t}-rtl`]:{direction:"rtl",[`${t}-nav`]:{[`${t}-tab`]:{margin:{_skip_check_:!0,value:n},[`${t}-tab:last-of-type`]:{marginLeft:{_skip_check_:!0,value:0}},[r]:{marginRight:{_skip_check_:!0,value:0},marginLeft:{_skip_check_:!0,value:X(e.marginSM)}},[`${t}-tab-remove`]:{marginRight:{_skip_check_:!0,value:X(e.marginXS)},marginLeft:{_skip_check_:!0,value:X(i(e.marginXXS).mul(-1).equal())},[r]:{margin:0}}}},[`&${t}-left`]:{[`> ${t}-nav`]:{order:1},[`> ${t}-content-holder`]:{order:0}},[`&${t}-right`]:{[`> ${t}-nav`]:{order:0},[`> ${t}-content-holder`]:{order:1}},[`&${t}-card${t}-top, &${t}-card${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab + ${t}-tab`]:{marginRight:{_skip_check_:!0,value:o},marginLeft:{_skip_check_:!0,value:0}}}}},[`${t}-dropdown-rtl`]:{direction:"rtl"},[`${t}-menu-item`]:{[`${t}-dropdown-rtl`]:{textAlign:{_skip_check_:!0,value:"right"}}}}},hk=e=>{const{componentCls:t,tabsCardPadding:n,cardHeight:r,cardGutter:o,itemHoverColor:i,itemActiveColor:a,colorBorderSecondary:l}=e;return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),{display:"flex",[`> ${t}-nav, > div > ${t}-nav`]:{position:"relative",display:"flex",flex:"none",alignItems:"center",[`${t}-nav-wrap`]:{position:"relative",display:"flex",flex:"auto",alignSelf:"stretch",overflow:"hidden",whiteSpace:"nowrap",transform:"translate(0)","&::before, &::after":{position:"absolute",zIndex:1,opacity:0,transition:`opacity ${e.motionDurationSlow}`,content:"''",pointerEvents:"none"}},[`${t}-nav-list`]:{position:"relative",display:"flex",transition:`opacity ${e.motionDurationSlow}`},[`${t}-nav-operations`]:{display:"flex",alignSelf:"stretch"},[`${t}-nav-operations-hidden`]:{position:"absolute",visibility:"hidden",pointerEvents:"none"},[`${t}-nav-more`]:{position:"relative",padding:n,background:"transparent",border:0,color:e.colorText,"&::after":{position:"absolute",right:{_skip_check_:!0,value:0},bottom:0,left:{_skip_check_:!0,value:0},height:e.calc(e.controlHeightLG).div(8).equal(),transform:"translateY(100%)",content:"''"}},[`${t}-nav-add`]:Object.assign({minWidth:r,minHeight:r,marginLeft:{_skip_check_:!0,value:o},padding:`0 ${X(e.paddingXS)}`,background:"transparent",border:`${X(e.lineWidth)} ${e.lineType} ${l}`,borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`,outline:"none",cursor:"pointer",color:e.colorText,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOut}`,"&:hover":{color:i},"&:active, &:focus:not(:focus-visible)":{color:a}},Xd(e))},[`${t}-extra-content`]:{flex:"none"},[`${t}-ink-bar`]:{position:"absolute",background:e.inkBarColor,pointerEvents:"none"}}),pk(e)),{[`${t}-content`]:{position:"relative",width:"100%"},[`${t}-content-holder`]:{flex:"auto",minWidth:0,minHeight:0},[`${t}-tabpane`]:{outline:"none","&-hidden":{display:"none"}}}),[`${t}-centered`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-nav-wrap`]:{[`&:not([class*='${t}-nav-wrap-ping'])`]:{justifyContent:"center"}}}}}},mk=e=>{const t=e.controlHeightLG;return{zIndexPopup:e.zIndexPopupBase+50,cardBg:e.colorFillAlter,cardHeight:t,cardPadding:`${(t-Math.round(e.fontSize*e.lineHeight))/2-e.lineWidth}px ${e.padding}px`,cardPaddingSM:`${e.paddingXXS*1.5}px ${e.padding}px`,cardPaddingLG:`${e.paddingXS}px ${e.padding}px ${e.paddingXXS*1.5}px`,titleFontSize:e.fontSize,titleFontSizeLG:e.fontSizeLG,titleFontSizeSM:e.fontSize,inkBarColor:e.colorPrimary,horizontalMargin:`0 0 ${e.margin}px 0`,horizontalItemGutter:32,horizontalItemMargin:"",horizontalItemMarginRTL:"",horizontalItemPadding:`${e.paddingSM}px 0`,horizontalItemPaddingSM:`${e.paddingXS}px 0`,horizontalItemPaddingLG:`${e.padding}px 0`,verticalItemPadding:`${e.paddingXS}px ${e.paddingLG}px`,verticalItemMargin:`${e.margin}px 0 0 0`,itemColor:e.colorText,itemSelectedColor:e.colorPrimary,itemHoverColor:e.colorPrimaryHover,itemActiveColor:e.colorPrimaryActive,cardGutter:e.marginXXS/2}},yk=vn("Tabs",e=>{const t=$t(e,{tabsCardPadding:e.cardPadding,dropdownEdgeChildVerticalPadding:e.paddingXXS,tabsActiveTextShadow:"0 0 0.25px currentcolor",tabsDropdownHeight:200,tabsDropdownWidth:120,tabsHorizontalItemMargin:`0 0 0 ${X(e.horizontalItemGutter)}`,tabsHorizontalItemMarginRTL:`0 0 0 ${X(e.horizontalItemGutter)}`});return[vk(t),gk(t),fk(t),dk(t),uk(t),hk(t),ck(t)]},mk),bk=()=>null,Sk=bk;var Ck=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var t,n,r,o,i,a,l;const{type:s,className:c,rootClassName:u,size:d,onEdit:v,hideAdd:h,centered:g,addIcon:p,moreIcon:b,popupClassName:m,children:y,items:S,animated:x,style:$,indicatorSize:E,indicator:w}=e,R=Ck(e,["type","className","rootClassName","size","onEdit","hideAdd","centered","addIcon","moreIcon","popupClassName","children","items","animated","style","indicatorSize","indicator"]),{prefixCls:P}=R,{direction:N,tabs:I,getPrefixCls:z,getPopupContainer:F}=f.exports.useContext(ot),T=z("tabs",P),D=no(T),[_,O,M]=yk(T,D);let L;s==="editable-card"&&(L={onEdit:(Y,K)=>{let{key:q,event:ee}=K;v==null||v(Y==="add"?ee:q,Y)},removeIcon:C(eo,{}),addIcon:(p!=null?p:I==null?void 0:I.addIcon)||C(BP,{}),showAdd:h!==!0});const A=z(),B=So(d),k=lk(S,y),j=ok(T,x),H=Object.assign(Object.assign({},I==null?void 0:I.style),$),W={align:(t=w==null?void 0:w.align)!==null&&t!==void 0?t:(n=I==null?void 0:I.indicator)===null||n===void 0?void 0:n.align,size:(a=(o=(r=w==null?void 0:w.size)!==null&&r!==void 0?r:E)!==null&&o!==void 0?o:(i=I==null?void 0:I.indicator)===null||i===void 0?void 0:i.size)!==null&&a!==void 0?a:I==null?void 0:I.indicatorSize};return _(C(nk,{...Object.assign({direction:N,getPopupContainer:F,moreTransitionName:`${A}-slide-up`},R,{items:k,className:te({[`${T}-${B}`]:B,[`${T}-card`]:["card","editable-card"].includes(s),[`${T}-editable-card`]:s==="editable-card",[`${T}-centered`]:g},I==null?void 0:I.className,c,u,O,M,D),popupClassName:te(m,O,M,D),style:H,editable:L,moreIcon:(l=b!=null?b:I==null?void 0:I.moreIcon)!==null&&l!==void 0?l:C(JI,{}),prefixCls:T,animated:j,indicator:W})}))};g$.TabPane=Sk;const xk=g$;var wk=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var{prefixCls:t,className:n,hoverable:r=!0}=e,o=wk(e,["prefixCls","className","hoverable"]);const{getPrefixCls:i}=f.exports.useContext(ot),a=i("card",t),l=te(`${a}-grid`,n,{[`${a}-grid-hoverable`]:r});return C("div",{...Object.assign({},o,{className:l})})},h$=$k,Ek=e=>{const{antCls:t,componentCls:n,headerHeight:r,cardPaddingBase:o,tabsMarginBottom:i}=e;return Object.assign(Object.assign({display:"flex",justifyContent:"center",flexDirection:"column",minHeight:r,marginBottom:-1,padding:`0 ${X(o)}`,color:e.colorTextHeading,fontWeight:e.fontWeightStrong,fontSize:e.headerFontSize,background:e.headerBg,borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorderSecondary}`,borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`},Us()),{"&-wrapper":{width:"100%",display:"flex",alignItems:"center"},"&-title":Object.assign(Object.assign({display:"inline-block",flex:1},ei),{[` + > ${n}-typography, + > ${n}-typography-edit-content + `]:{insetInlineStart:0,marginTop:0,marginBottom:0}}),[`${t}-tabs-top`]:{clear:"both",marginBottom:i,color:e.colorText,fontWeight:"normal",fontSize:e.fontSize,"&-bar":{borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorderSecondary}`}}})},Mk=e=>{const{cardPaddingBase:t,colorBorderSecondary:n,cardShadow:r,lineWidth:o}=e;return{width:"33.33%",padding:t,border:0,borderRadius:0,boxShadow:` + ${X(o)} 0 0 0 ${n}, + 0 ${X(o)} 0 0 ${n}, + ${X(o)} ${X(o)} 0 0 ${n}, + ${X(o)} 0 0 0 ${n} inset, + 0 ${X(o)} 0 0 ${n} inset; + `,transition:`all ${e.motionDurationMid}`,"&-hoverable:hover":{position:"relative",zIndex:1,boxShadow:r}}},Ok=e=>{const{componentCls:t,iconCls:n,actionsLiMargin:r,cardActionsIconSize:o,colorBorderSecondary:i,actionsBg:a}=e;return Object.assign(Object.assign({margin:0,padding:0,listStyle:"none",background:a,borderTop:`${X(e.lineWidth)} ${e.lineType} ${i}`,display:"flex",borderRadius:`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},Us()),{"& > li":{margin:r,color:e.colorTextDescription,textAlign:"center","> span":{position:"relative",display:"block",minWidth:e.calc(e.cardActionsIconSize).mul(2).equal(),fontSize:e.fontSize,lineHeight:e.lineHeight,cursor:"pointer","&:hover":{color:e.colorPrimary,transition:`color ${e.motionDurationMid}`},[`a:not(${t}-btn), > ${n}`]:{display:"inline-block",width:"100%",color:e.colorTextDescription,lineHeight:X(e.fontHeight),transition:`color ${e.motionDurationMid}`,"&:hover":{color:e.colorPrimary}},[`> ${n}`]:{fontSize:o,lineHeight:X(e.calc(o).mul(e.lineHeight).equal())}},"&:not(:last-child)":{borderInlineEnd:`${X(e.lineWidth)} ${e.lineType} ${i}`}}})},Rk=e=>Object.assign(Object.assign({margin:`${X(e.calc(e.marginXXS).mul(-1).equal())} 0`,display:"flex"},Us()),{"&-avatar":{paddingInlineEnd:e.padding},"&-detail":{overflow:"hidden",flex:1,"> div:not(:last-child)":{marginBottom:e.marginXS}},"&-title":Object.assign({color:e.colorTextHeading,fontWeight:e.fontWeightStrong,fontSize:e.fontSizeLG},ei),"&-description":{color:e.colorTextDescription}}),Ik=e=>{const{componentCls:t,cardPaddingBase:n,colorFillAlter:r}=e;return{[`${t}-head`]:{padding:`0 ${X(n)}`,background:r,"&-title":{fontSize:e.fontSize}},[`${t}-body`]:{padding:`${X(e.padding)} ${X(n)}`}}},Pk=e=>{const{componentCls:t}=e;return{overflow:"hidden",[`${t}-body`]:{userSelect:"none"}}},Tk=e=>{const{antCls:t,componentCls:n,cardShadow:r,cardHeadPadding:o,colorBorderSecondary:i,boxShadowTertiary:a,cardPaddingBase:l,extraColor:s}=e;return{[n]:Object.assign(Object.assign({},Qt(e)),{position:"relative",background:e.colorBgContainer,borderRadius:e.borderRadiusLG,[`&:not(${n}-bordered)`]:{boxShadow:a},[`${n}-head`]:Ek(e),[`${n}-extra`]:{marginInlineStart:"auto",color:s,fontWeight:"normal",fontSize:e.fontSize},[`${n}-body`]:Object.assign({padding:l,borderRadius:` 0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},Us()),[`${n}-grid`]:Mk(e),[`${n}-cover`]:{"> *":{display:"block",width:"100%"},[`img, img + ${t}-image-mask`]:{borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`}},[`${n}-actions`]:Ok(e),[`${n}-meta`]:Rk(e)}),[`${n}-bordered`]:{border:`${X(e.lineWidth)} ${e.lineType} ${i}`,[`${n}-cover`]:{marginTop:-1,marginInlineStart:-1,marginInlineEnd:-1}},[`${n}-hoverable`]:{cursor:"pointer",transition:`box-shadow ${e.motionDurationMid}, border-color ${e.motionDurationMid}`,"&:hover":{borderColor:"transparent",boxShadow:r}},[`${n}-contain-grid`]:{borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0 `,[`${n}-body`]:{display:"flex",flexWrap:"wrap"},[`&:not(${n}-loading) ${n}-body`]:{marginBlockStart:e.calc(e.lineWidth).mul(-1).equal(),marginInlineStart:e.calc(e.lineWidth).mul(-1).equal(),padding:0}},[`${n}-contain-tabs`]:{[`> ${n}-head`]:{minHeight:0,[`${n}-head-title, ${n}-extra`]:{paddingTop:o}}},[`${n}-type-inner`]:Ik(e),[`${n}-loading`]:Pk(e),[`${n}-rtl`]:{direction:"rtl"}}},Nk=e=>{const{componentCls:t,cardPaddingSM:n,headerHeightSM:r,headerFontSizeSM:o}=e;return{[`${t}-small`]:{[`> ${t}-head`]:{minHeight:r,padding:`0 ${X(n)}`,fontSize:o,[`> ${t}-head-wrapper`]:{[`> ${t}-extra`]:{fontSize:e.fontSize}}},[`> ${t}-body`]:{padding:n}},[`${t}-small${t}-contain-tabs`]:{[`> ${t}-head`]:{[`${t}-head-title, ${t}-extra`]:{paddingTop:0,display:"flex",alignItems:"center"}}}}},_k=e=>({headerBg:"transparent",headerFontSize:e.fontSizeLG,headerFontSizeSM:e.fontSize,headerHeight:e.fontSizeLG*e.lineHeightLG+e.padding*2,headerHeightSM:e.fontSize*e.lineHeight+e.paddingXS*2,actionsBg:e.colorBgContainer,actionsLiMargin:`${e.paddingSM}px 0`,tabsMarginBottom:-e.padding-e.lineWidth,extraColor:e.colorText}),Ak=vn("Card",e=>{const t=$t(e,{cardShadow:e.boxShadowCard,cardHeadPadding:e.padding,cardPaddingBase:e.paddingLG,cardActionsIconSize:e.fontSize,cardPaddingSM:12});return[Tk(t),Nk(t)]},_k);var i1=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{actionClasses:t,actions:n=[],actionStyle:r}=e;return C("ul",{className:t,style:r,children:n.map((o,i)=>{const a=`action-${i}`;return C("li",{style:{width:`${100/n.length}%`},children:C("span",{children:o})},a)})})},Lk=f.exports.forwardRef((e,t)=>{const{prefixCls:n,className:r,rootClassName:o,style:i,extra:a,headStyle:l={},bodyStyle:s={},title:c,loading:u,bordered:d=!0,size:v,type:h,cover:g,actions:p,tabList:b,children:m,activeTabKey:y,defaultActiveTabKey:S,tabBarExtraContent:x,hoverable:$,tabProps:E={},classNames:w,styles:R}=e,P=i1(e,["prefixCls","className","rootClassName","style","extra","headStyle","bodyStyle","title","loading","bordered","size","type","cover","actions","tabList","children","activeTabKey","defaultActiveTabKey","tabBarExtraContent","hoverable","tabProps","classNames","styles"]),{getPrefixCls:N,direction:I,card:z}=f.exports.useContext(ot),F=pe=>{var oe;(oe=e.onTabChange)===null||oe===void 0||oe.call(e,pe)},T=pe=>{var oe;return te((oe=z==null?void 0:z.classNames)===null||oe===void 0?void 0:oe[pe],w==null?void 0:w[pe])},D=pe=>{var oe;return Object.assign(Object.assign({},(oe=z==null?void 0:z.styles)===null||oe===void 0?void 0:oe[pe]),R==null?void 0:R[pe])},_=f.exports.useMemo(()=>{let pe=!1;return f.exports.Children.forEach(m,oe=>{oe&&oe.type&&oe.type===h$&&(pe=!0)}),pe},[m]),O=N("card",n),[M,L,A]=Ak(O),B=C(zF,{loading:!0,active:!0,paragraph:{rows:4},title:!1,children:m}),k=y!==void 0,j=Object.assign(Object.assign({},E),{[k?"activeKey":"defaultActiveKey"]:k?y:S,tabBarExtraContent:x});let H;const W=So(v),K=b?C(xk,{...Object.assign({size:!W||W==="default"?"large":W},j,{className:`${O}-head-tabs`,onChange:F,items:b.map(pe=>{var{tab:oe}=pe,se=i1(pe,["tab"]);return Object.assign({label:oe},se)})})}):null;if(c||a||K){const pe=te(`${O}-head`,T("header")),oe=te(`${O}-head-title`,T("title")),se=te(`${O}-extra`,T("extra")),le=Object.assign(Object.assign({},l),D("header"));H=ie("div",{className:pe,style:le,children:[ie("div",{className:`${O}-head-wrapper`,children:[c&&C("div",{className:oe,style:D("title"),children:c}),a&&C("div",{className:se,style:D("extra"),children:a})]}),K]})}const q=te(`${O}-cover`,T("cover")),ee=g?C("div",{className:q,style:D("cover"),children:g}):null,Z=te(`${O}-body`,T("body")),Q=Object.assign(Object.assign({},s),D("body")),ne=C("div",{className:Z,style:Q,children:u?B:m}),ae=te(`${O}-actions`,T("actions")),J=p&&p.length?C(Dk,{actionClasses:ae,actionStyle:D("actions"),actions:p}):null,re=lr(P,["onTabChange"]),fe=te(O,z==null?void 0:z.className,{[`${O}-loading`]:u,[`${O}-bordered`]:d,[`${O}-hoverable`]:$,[`${O}-contain-grid`]:_,[`${O}-contain-tabs`]:b&&b.length,[`${O}-${W}`]:W,[`${O}-type-${h}`]:!!h,[`${O}-rtl`]:I==="rtl"},r,o,L,A),ve=Object.assign(Object.assign({},z==null?void 0:z.style),i);return M(ie("div",{...Object.assign({ref:t},re,{className:fe,style:ve}),children:[H,ee,ne,J]}))}),zk=Lk;var Fk=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:t,className:n,avatar:r,title:o,description:i}=e,a=Fk(e,["prefixCls","className","avatar","title","description"]),{getPrefixCls:l}=f.exports.useContext(ot),s=l("card",t),c=te(`${s}-meta`,n),u=r?C("div",{className:`${s}-meta-avatar`,children:r}):null,d=o?C("div",{className:`${s}-meta-title`,children:o}):null,v=i?C("div",{className:`${s}-meta-description`,children:i}):null,h=d||v?ie("div",{className:`${s}-meta-detail`,children:[d,v]}):null;return ie("div",{...Object.assign({},a,{className:c}),children:[u,h]})},Bk=kk,Pm=zk;Pm.Grid=h$;Pm.Meta=Bk;const m$=Pm;function jk(e,t,n){var r=n||{},o=r.noTrailing,i=o===void 0?!1:o,a=r.noLeading,l=a===void 0?!1:a,s=r.debounceMode,c=s===void 0?void 0:s,u,d=!1,v=0;function h(){u&&clearTimeout(u)}function g(b){var m=b||{},y=m.upcomingOnly,S=y===void 0?!1:y;h(),d=!S}function p(){for(var b=arguments.length,m=new Array(b),y=0;ye?l?(v=Date.now(),i||(u=setTimeout(c?E:$,e))):$():i!==!0&&(u=setTimeout(c?E:$,c===void 0?e-x:e))}return p.cancel=g,p}function Hk(e,t,n){var r=n||{},o=r.atBegin,i=o===void 0?!1:o;return jk(e,t,{debounceMode:i!==!1})}function Wk(e){return!!(e.addonBefore||e.addonAfter)}function Vk(e){return!!(e.prefix||e.suffix||e.allowClear)}function od(e,t,n,r){if(!!n){var o=t;if(t.type==="click"){var i=e.cloneNode(!0);o=Object.create(t,{target:{value:i},currentTarget:{value:i}}),i.value="",n(o);return}if(e.type!=="file"&&r!==void 0){var a=e.cloneNode(!0);o=Object.create(t,{target:{value:a},currentTarget:{value:a}}),a.value=r,n(o);return}n(o)}}function Uk(e,t){if(!!e){e.focus(t);var n=t||{},r=n.cursor;if(r){var o=e.value.length;switch(r){case"start":e.setSelectionRange(0,0);break;case"end":e.setSelectionRange(o,o);break;default:e.setSelectionRange(0,o)}}}}var y$=function(t){var n,r,o=t.inputElement,i=t.children,a=t.prefixCls,l=t.prefix,s=t.suffix,c=t.addonBefore,u=t.addonAfter,d=t.className,v=t.style,h=t.disabled,g=t.readOnly,p=t.focused,b=t.triggerFocus,m=t.allowClear,y=t.value,S=t.handleReset,x=t.hidden,$=t.classes,E=t.classNames,w=t.dataAttrs,R=t.styles,P=t.components,N=i!=null?i:o,I=(P==null?void 0:P.affixWrapper)||"span",z=(P==null?void 0:P.groupWrapper)||"span",F=(P==null?void 0:P.wrapper)||"span",T=(P==null?void 0:P.groupAddon)||"span",D=f.exports.useRef(null),_=function(J){var re;(re=D.current)!==null&&re!==void 0&&re.contains(J.target)&&(b==null||b())},O=Vk(t),M=f.exports.cloneElement(N,{value:y,className:te(N.props.className,!O&&(E==null?void 0:E.variant))||null});if(O){var L,A=null;if(m){var B,k=!h&&!g&&y,j="".concat(a,"-clear-icon"),H=Qe(m)==="object"&&m!==null&&m!==void 0&&m.clearIcon?m.clearIcon:"\u2716";A=C("span",{onClick:S,onMouseDown:function(J){return J.preventDefault()},className:te(j,(B={},V(B,"".concat(j,"-hidden"),!k),V(B,"".concat(j,"-has-suffix"),!!s),B)),role:"button",tabIndex:-1,children:H})}var W="".concat(a,"-affix-wrapper"),Y=te(W,(L={},V(L,"".concat(a,"-disabled"),h),V(L,"".concat(W,"-disabled"),h),V(L,"".concat(W,"-focused"),p),V(L,"".concat(W,"-readonly"),g),V(L,"".concat(W,"-input-with-clear-btn"),s&&m&&y),L),$==null?void 0:$.affixWrapper,E==null?void 0:E.affixWrapper,E==null?void 0:E.variant),K=(s||m)&&ie("span",{className:te("".concat(a,"-suffix"),E==null?void 0:E.suffix),style:R==null?void 0:R.suffix,children:[A,s]});M=ie(I,{className:Y,style:R==null?void 0:R.affixWrapper,onClick:_,...w==null?void 0:w.affixWrapper,ref:D,children:[l&&C("span",{className:te("".concat(a,"-prefix"),E==null?void 0:E.prefix),style:R==null?void 0:R.prefix,children:l}),M,K]})}if(Wk(t)){var q="".concat(a,"-group"),ee="".concat(q,"-addon"),Z="".concat(q,"-wrapper"),Q=te("".concat(a,"-wrapper"),q,$==null?void 0:$.wrapper,E==null?void 0:E.wrapper),ne=te(Z,V({},"".concat(Z,"-disabled"),h),$==null?void 0:$.group,E==null?void 0:E.groupWrapper);M=C(z,{className:ne,children:ie(F,{className:Q,children:[c&&C(T,{className:ee,children:c}),M,u&&C(T,{className:ee,children:u})]})})}return lt.cloneElement(M,{className:te((n=M.props)===null||n===void 0?void 0:n.className,d)||null,style:U(U({},(r=M.props)===null||r===void 0?void 0:r.style),v),hidden:x})},Yk=["show"];function b$(e,t){return f.exports.useMemo(function(){var n={};t&&(n.show=Qe(t)==="object"&&t.formatter?t.formatter:!!t),n=U(U({},n),e);var r=n,o=r.show,i=Je(r,Yk);return U(U({},i),{},{show:!!o,showFormatter:typeof o=="function"?o:void 0,strategy:i.strategy||function(a){return a.length}})},[e,t])}var Gk=["autoComplete","onChange","onFocus","onBlur","onPressEnter","onKeyDown","prefixCls","disabled","htmlSize","className","maxLength","suffix","showCount","count","type","classes","classNames","styles","onCompositionStart","onCompositionEnd"],Kk=f.exports.forwardRef(function(e,t){var n=e.autoComplete,r=e.onChange,o=e.onFocus,i=e.onBlur,a=e.onPressEnter,l=e.onKeyDown,s=e.prefixCls,c=s===void 0?"rc-input":s,u=e.disabled,d=e.htmlSize,v=e.className,h=e.maxLength,g=e.suffix,p=e.showCount,b=e.count,m=e.type,y=m===void 0?"text":m,S=e.classes,x=e.classNames,$=e.styles,E=e.onCompositionStart,w=e.onCompositionEnd,R=Je(e,Gk),P=f.exports.useState(!1),N=G(P,2),I=N[0],z=N[1],F=f.exports.useRef(!1),T=f.exports.useRef(null),D=function(se){T.current&&Uk(T.current,se)},_=kt(e.defaultValue,{value:e.value}),O=G(_,2),M=O[0],L=O[1],A=M==null?"":String(M),B=f.exports.useState(null),k=G(B,2),j=k[0],H=k[1],W=b$(b,p),Y=W.max||h,K=W.strategy(A),q=!!Y&&K>Y;f.exports.useImperativeHandle(t,function(){return{focus:D,blur:function(){var se;(se=T.current)===null||se===void 0||se.blur()},setSelectionRange:function(se,le,Ce){var ce;(ce=T.current)===null||ce===void 0||ce.setSelectionRange(se,le,Ce)},select:function(){var se;(se=T.current)===null||se===void 0||se.select()},input:T.current}}),f.exports.useEffect(function(){z(function(oe){return oe&&u?!1:oe})},[u]);var ee=function(se,le,Ce){var ce=le;if(!F.current&&W.exceedFormatter&&W.max&&W.strategy(le)>W.max){if(ce=W.exceedFormatter(le,{max:W.max}),le!==ce){var de,xe;H([((de=T.current)===null||de===void 0?void 0:de.selectionStart)||0,((xe=T.current)===null||xe===void 0?void 0:xe.selectionEnd)||0])}}else if(Ce.source==="compositionEnd")return;L(ce),T.current&&od(T.current,se,r,ce)};f.exports.useEffect(function(){if(j){var oe;(oe=T.current)===null||oe===void 0||oe.setSelectionRange.apply(oe,Oe(j))}},[j]);var Z=function(se){ee(se,se.target.value,{source:"change"})},Q=function(se){F.current=!1,ee(se,se.currentTarget.value,{source:"compositionEnd"}),w==null||w(se)},ne=function(se){a&&se.key==="Enter"&&a(se),l==null||l(se)},ae=function(se){z(!0),o==null||o(se)},J=function(se){z(!1),i==null||i(se)},re=function(se){L(""),D(),T.current&&od(T.current,se,r)},fe=q&&"".concat(c,"-out-of-range"),ve=function(){var se=lr(e,["prefixCls","onPressEnter","addonBefore","addonAfter","prefix","suffix","allowClear","defaultValue","showCount","count","classes","htmlSize","styles","classNames"]);return C("input",{autoComplete:n,...se,onChange:Z,onFocus:ae,onBlur:J,onKeyDown:ne,className:te(c,V({},"".concat(c,"-disabled"),u),x==null?void 0:x.input),style:$==null?void 0:$.input,ref:T,size:d,type:y,onCompositionStart:function(Ce){F.current=!0,E==null||E(Ce)},onCompositionEnd:Q})},pe=function(){var se=Number(Y)>0;if(g||W.show){var le=W.showFormatter?W.showFormatter({value:A,count:K,maxLength:Y}):"".concat(K).concat(se?" / ".concat(Y):"");return ie(Tt,{children:[W.show&&C("span",{className:te("".concat(c,"-show-count-suffix"),V({},"".concat(c,"-show-count-has-suffix"),!!g),x==null?void 0:x.count),style:U({},$==null?void 0:$.count),children:le}),g]})}return null};return C(y$,{...R,prefixCls:c,className:te(v,fe),handleReset:re,value:A,focused:I,triggerFocus:D,suffix:pe(),disabled:u,classes:S,classNames:x,styles:$,children:ve()})});const qk=e=>{const{getPrefixCls:t,direction:n}=f.exports.useContext(ot),{prefixCls:r,className:o}=e,i=t("input-group",r),a=t("input"),[l,s]=Im(a),c=te(i,{[`${i}-lg`]:e.size==="large",[`${i}-sm`]:e.size==="small",[`${i}-compact`]:e.compact,[`${i}-rtl`]:n==="rtl"},s,o),u=f.exports.useContext(Jr),d=f.exports.useMemo(()=>Object.assign(Object.assign({},u),{isFormItemInput:!1}),[u]);return l(C("span",{className:c,style:e.style,onMouseEnter:e.onMouseEnter,onMouseLeave:e.onMouseLeave,onFocus:e.onFocus,onBlur:e.onBlur,children:C(Jr.Provider,{value:d,children:e.children})}))},Xk=qk;function S$(e,t){const n=f.exports.useRef([]),r=()=>{n.current.push(setTimeout(()=>{var o,i,a,l;((o=e.current)===null||o===void 0?void 0:o.input)&&((i=e.current)===null||i===void 0?void 0:i.input.getAttribute("type"))==="password"&&((a=e.current)===null||a===void 0?void 0:a.input.hasAttribute("value"))&&((l=e.current)===null||l===void 0||l.input.removeAttribute("value"))}))};return f.exports.useEffect(()=>(t&&r(),()=>n.current.forEach(o=>{o&&clearTimeout(o)})),[]),r}function Qk(e){return!!(e.prefix||e.suffix||e.allowClear||e.showCount)}const Zk=e=>{let t;return typeof e=="object"&&(e==null?void 0:e.clearIcon)?t=e:e&&(t={clearIcon:C(Nd,{})}),t},Jk=Zk;var e7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n;const{prefixCls:r,bordered:o=!0,status:i,size:a,disabled:l,onBlur:s,onFocus:c,suffix:u,allowClear:d,addonAfter:v,addonBefore:h,className:g,style:p,styles:b,rootClassName:m,onChange:y,classNames:S,variant:x}=e,$=e7(e,["prefixCls","bordered","status","size","disabled","onBlur","onFocus","suffix","allowClear","addonAfter","addonBefore","className","style","styles","rootClassName","onChange","classNames","variant"]),{getPrefixCls:E,direction:w,input:R}=lt.useContext(ot),P=E("input",r),N=f.exports.useRef(null),I=no(P),[z,F,T]=Im(P,I),{compactSize:D,compactItemClassnames:_}=ef(P,w),O=So(ae=>{var J;return(J=a!=null?a:D)!==null&&J!==void 0?J:ae}),M=lt.useContext(rl),L=l!=null?l:M,{status:A,hasFeedback:B,feedbackIcon:k}=f.exports.useContext(Jr),j=dm(A,i),H=Qk(e)||!!B;f.exports.useRef(H);const W=S$(N,!0),Y=ae=>{W(),s==null||s(ae)},K=ae=>{W(),c==null||c(ae)},q=ae=>{W(),y==null||y(ae)},ee=(B||u)&&ie(Tt,{children:[u,B&&k]}),Z=Jk(d),[Q,ne]=vm(x,o);return z(C(Kk,{...Object.assign({ref:xr(t,N),prefixCls:P,autoComplete:R==null?void 0:R.autoComplete},$,{disabled:L,onBlur:Y,onFocus:K,style:Object.assign(Object.assign({},R==null?void 0:R.style),p),styles:Object.assign(Object.assign({},R==null?void 0:R.styles),b),suffix:ee,allowClear:Z,className:te(g,m,T,I,_,R==null?void 0:R.className),onChange:q,addonAfter:v&&C(ig,{children:C(db,{override:!0,status:!0,children:v})}),addonBefore:h&&C(ig,{children:C(db,{override:!0,status:!0,children:h})}),classNames:Object.assign(Object.assign(Object.assign({},S),R==null?void 0:R.classNames),{input:te({[`${P}-sm`]:O==="small",[`${P}-lg`]:O==="large",[`${P}-rtl`]:w==="rtl"},S==null?void 0:S.input,(n=R==null?void 0:R.classNames)===null||n===void 0?void 0:n.input,F),variant:te({[`${P}-${Q}`]:ne},ed(P,j)),affixWrapper:te({[`${P}-affix-wrapper-sm`]:O==="small",[`${P}-affix-wrapper-lg`]:O==="large",[`${P}-affix-wrapper-rtl`]:w==="rtl"},F),wrapper:te({[`${P}-group-rtl`]:w==="rtl"},F),groupWrapper:te({[`${P}-group-wrapper-sm`]:O==="small",[`${P}-group-wrapper-lg`]:O==="large",[`${P}-group-wrapper-rtl`]:w==="rtl",[`${P}-group-wrapper-${Q}`]:ne},ed(`${P}-group-wrapper`,j,B),F)})})}))}),Tm=n7;var r7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);oe?C(sx,{}):C(rP,{}),i7={click:"onClick",hover:"onMouseOver"},a7=f.exports.forwardRef((e,t)=>{const{visibilityToggle:n=!0}=e,r=typeof n=="object"&&n.visible!==void 0,[o,i]=f.exports.useState(()=>r?n.visible:!1),a=f.exports.useRef(null);f.exports.useEffect(()=>{r&&i(n.visible)},[r,n]);const l=S$(a),s=()=>{const{disabled:$}=e;$||(o&&l(),i(E=>{var w;const R=!E;return typeof n=="object"&&((w=n.onVisibleChange)===null||w===void 0||w.call(n,R)),R}))},c=$=>{const{action:E="click",iconRender:w=o7}=e,R=i7[E]||"",P=w(o),N={[R]:s,className:`${$}-icon`,key:"passwordIcon",onMouseDown:I=>{I.preventDefault()},onMouseUp:I=>{I.preventDefault()}};return f.exports.cloneElement(f.exports.isValidElement(P)?P:C("span",{children:P}),N)},{className:u,prefixCls:d,inputPrefixCls:v,size:h}=e,g=r7(e,["className","prefixCls","inputPrefixCls","size"]),{getPrefixCls:p}=f.exports.useContext(ot),b=p("input",v),m=p("input-password",d),y=n&&c(m),S=te(m,u,{[`${m}-${h}`]:!!h}),x=Object.assign(Object.assign({},lr(g,["suffix","iconRender","visibilityToggle"])),{type:o?"text":"password",className:S,prefixCls:b,suffix:y});return h&&(x.size=h),C(Tm,{...Object.assign({ref:xr(t,a)},x)})}),l7=a7;var s7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:n,inputPrefixCls:r,className:o,size:i,suffix:a,enterButton:l=!1,addonAfter:s,loading:c,disabled:u,onSearch:d,onChange:v,onCompositionStart:h,onCompositionEnd:g}=e,p=s7(e,["prefixCls","inputPrefixCls","className","size","suffix","enterButton","addonAfter","loading","disabled","onSearch","onChange","onCompositionStart","onCompositionEnd"]),{getPrefixCls:b,direction:m}=f.exports.useContext(ot),y=f.exports.useRef(!1),S=b("input-search",n),x=b("input",r),{compactSize:$}=ef(S,m),E=So(A=>{var B;return(B=i!=null?i:$)!==null&&B!==void 0?B:A}),w=f.exports.useRef(null),R=A=>{A&&A.target&&A.type==="click"&&d&&d(A.target.value,A,{source:"clear"}),v&&v(A)},P=A=>{var B;document.activeElement===((B=w.current)===null||B===void 0?void 0:B.input)&&A.preventDefault()},N=A=>{var B,k;d&&d((k=(B=w.current)===null||B===void 0?void 0:B.input)===null||k===void 0?void 0:k.value,A,{source:"input"})},I=A=>{y.current||c||N(A)},z=typeof l=="boolean"?C(_d,{}):null,F=`${S}-button`;let T;const D=l||{},_=D.type&&D.type.__ANT_BUTTON===!0;_||D.type==="button"?T=ti(D,Object.assign({onMouseDown:P,onClick:A=>{var B,k;(k=(B=D==null?void 0:D.props)===null||B===void 0?void 0:B.onClick)===null||k===void 0||k.call(B,A),N(A)},key:"enterButton"},_?{className:F,size:E}:{})):T=C(Xu,{className:F,type:l?"primary":void 0,size:E,disabled:u,onMouseDown:P,onClick:N,loading:c,icon:z,children:l},"enterButton"),s&&(T=[T,ti(s,{key:"addonAfter"})]);const O=te(S,{[`${S}-rtl`]:m==="rtl",[`${S}-${E}`]:!!E,[`${S}-with-button`]:!!l},o),M=A=>{y.current=!0,h==null||h(A)},L=A=>{y.current=!1,g==null||g(A)};return C(Tm,{...Object.assign({ref:xr(w,t),onPressEnter:I},p,{size:E,onCompositionStart:M,onCompositionEnd:L,prefixCls:x,addonAfter:T,suffix:a,onChange:R,className:O,disabled:u})})}),u7=c7;var d7=` + min-height:0 !important; + max-height:none !important; + height:0 !important; + visibility:hidden !important; + overflow:hidden !important; + position:absolute !important; + z-index:-1000 !important; + top:0 !important; + right:0 !important; + pointer-events: none !important; +`,f7=["letter-spacing","line-height","padding-top","padding-bottom","font-family","font-weight","font-size","font-variant","text-rendering","text-transform","width","text-indent","padding-left","padding-right","border-width","box-sizing","word-break","white-space"],Ev={},dr;function v7(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=e.getAttribute("id")||e.getAttribute("data-reactid")||e.getAttribute("name");if(t&&Ev[n])return Ev[n];var r=window.getComputedStyle(e),o=r.getPropertyValue("box-sizing")||r.getPropertyValue("-moz-box-sizing")||r.getPropertyValue("-webkit-box-sizing"),i=parseFloat(r.getPropertyValue("padding-bottom"))+parseFloat(r.getPropertyValue("padding-top")),a=parseFloat(r.getPropertyValue("border-bottom-width"))+parseFloat(r.getPropertyValue("border-top-width")),l=f7.map(function(c){return"".concat(c,":").concat(r.getPropertyValue(c))}).join(";"),s={sizingStyle:l,paddingSize:i,borderSize:a,boxSizing:o};return t&&n&&(Ev[n]=s),s}function p7(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:null,r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:null;dr||(dr=document.createElement("textarea"),dr.setAttribute("tab-index","-1"),dr.setAttribute("aria-hidden","true"),document.body.appendChild(dr)),e.getAttribute("wrap")?dr.setAttribute("wrap",e.getAttribute("wrap")):dr.removeAttribute("wrap");var o=v7(e,t),i=o.paddingSize,a=o.borderSize,l=o.boxSizing,s=o.sizingStyle;dr.setAttribute("style","".concat(s,";").concat(d7)),dr.value=e.value||e.placeholder||"";var c=void 0,u=void 0,d,v=dr.scrollHeight;if(l==="border-box"?v+=a:l==="content-box"&&(v-=i),n!==null||r!==null){dr.value=" ";var h=dr.scrollHeight-i;n!==null&&(c=h*n,l==="border-box"&&(c=c+i+a),v=Math.max(c,v)),r!==null&&(u=h*r,l==="border-box"&&(u=u+i+a),d=v>u?"":"hidden",v=Math.min(u,v))}var g={height:v,overflowY:d,resize:"none"};return c&&(g.minHeight=c),u&&(g.maxHeight=u),g}var g7=["prefixCls","onPressEnter","defaultValue","value","autoSize","onResize","className","style","disabled","onChange","onInternalAutoSize"],Mv=0,Ov=1,Rv=2,h7=f.exports.forwardRef(function(e,t){var n=e,r=n.prefixCls;n.onPressEnter;var o=n.defaultValue,i=n.value,a=n.autoSize,l=n.onResize,s=n.className,c=n.style,u=n.disabled,d=n.onChange;n.onInternalAutoSize;var v=Je(n,g7),h=kt(o,{value:i,postState:function(H){return H!=null?H:""}}),g=G(h,2),p=g[0],b=g[1],m=function(H){b(H.target.value),d==null||d(H)},y=f.exports.useRef();f.exports.useImperativeHandle(t,function(){return{textArea:y.current}});var S=f.exports.useMemo(function(){return a&&Qe(a)==="object"?[a.minRows,a.maxRows]:[]},[a]),x=G(S,2),$=x[0],E=x[1],w=!!a,R=function(){try{if(document.activeElement===y.current){var H=y.current,W=H.selectionStart,Y=H.selectionEnd,K=H.scrollTop;y.current.setSelectionRange(W,Y),y.current.scrollTop=K}}catch{}},P=f.exports.useState(Rv),N=G(P,2),I=N[0],z=N[1],F=f.exports.useState(),T=G(F,2),D=T[0],_=T[1],O=function(){z(Mv)};Nt(function(){w&&O()},[i,$,E,w]),Nt(function(){if(I===Mv)z(Ov);else if(I===Ov){var j=p7(y.current,!1,$,E);z(Rv),_(j)}else R()},[I]);var M=f.exports.useRef(),L=function(){St.cancel(M.current)},A=function(H){I===Rv&&(l==null||l(H),a&&(L(),M.current=St(function(){O()})))};f.exports.useEffect(function(){return L},[]);var B=w?D:null,k=U(U({},c),B);return(I===Mv||I===Ov)&&(k.overflowY="hidden",k.overflowX="hidden"),C(mr,{onResize:A,disabled:!(a||l),children:C("textarea",{...v,ref:y,style:k,className:te(r,s,V({},"".concat(r,"-disabled"),u)),disabled:u,value:p,onChange:m})})}),m7=["defaultValue","value","onFocus","onBlur","onChange","allowClear","maxLength","onCompositionStart","onCompositionEnd","suffix","prefixCls","showCount","count","className","style","disabled","hidden","classNames","styles","onResize"],y7=lt.forwardRef(function(e,t){var n,r,o=e.defaultValue,i=e.value,a=e.onFocus,l=e.onBlur,s=e.onChange,c=e.allowClear,u=e.maxLength,d=e.onCompositionStart,v=e.onCompositionEnd,h=e.suffix,g=e.prefixCls,p=g===void 0?"rc-textarea":g,b=e.showCount,m=e.count,y=e.className,S=e.style,x=e.disabled,$=e.hidden,E=e.classNames,w=e.styles,R=e.onResize,P=Je(e,m7),N=kt(o,{value:i,defaultValue:o}),I=G(N,2),z=I[0],F=I[1],T=z==null?"":String(z),D=lt.useState(!1),_=G(D,2),O=_[0],M=_[1],L=lt.useRef(!1),A=lt.useState(null),B=G(A,2),k=B[0],j=B[1],H=f.exports.useRef(null),W=function(){var ge;return(ge=H.current)===null||ge===void 0?void 0:ge.textArea},Y=function(){W().focus()};f.exports.useImperativeHandle(t,function(){return{resizableTextArea:H.current,focus:Y,blur:function(){W().blur()}}}),f.exports.useEffect(function(){M(function(we){return!x&&we})},[x]);var K=lt.useState(null),q=G(K,2),ee=q[0],Z=q[1];lt.useEffect(function(){if(ee){var we;(we=W()).setSelectionRange.apply(we,Oe(ee))}},[ee]);var Q=b$(m,b),ne=(n=Q.max)!==null&&n!==void 0?n:u,ae=Number(ne)>0,J=Q.strategy(T),re=!!ne&&J>ne,fe=function(ge,Pe){var Se=Pe;!L.current&&Q.exceedFormatter&&Q.max&&Q.strategy(Pe)>Q.max&&(Se=Q.exceedFormatter(Pe,{max:Q.max}),Pe!==Se&&Z([W().selectionStart||0,W().selectionEnd||0])),F(Se),od(ge.currentTarget,ge,s,Se)},ve=function(ge){L.current=!0,d==null||d(ge)},pe=function(ge){L.current=!1,fe(ge,ge.currentTarget.value),v==null||v(ge)},oe=function(ge){fe(ge,ge.target.value)},se=function(ge){var Pe=P.onPressEnter,Se=P.onKeyDown;ge.key==="Enter"&&Pe&&Pe(ge),Se==null||Se(ge)},le=function(ge){M(!0),a==null||a(ge)},Ce=function(ge){M(!1),l==null||l(ge)},ce=function(ge){F(""),Y(),od(W(),ge,s)},de=h,xe;Q.show&&(Q.showFormatter?xe=Q.showFormatter({value:T,count:J,maxLength:ne}):xe="".concat(J).concat(ae?" / ".concat(ne):""),de=ie(Tt,{children:[de,C("span",{className:te("".concat(p,"-data-count"),E==null?void 0:E.count),style:w==null?void 0:w.count,children:xe})]}));var he=function(ge){var Pe;R==null||R(ge),(Pe=W())!==null&&Pe!==void 0&&Pe.style.height&&j(!0)},ke=!P.autoSize&&!b&&!c;return C(y$,{value:T,allowClear:c,handleReset:ce,suffix:de,prefixCls:p,classNames:U(U({},E),{},{affixWrapper:te(E==null?void 0:E.affixWrapper,(r={},V(r,"".concat(p,"-show-count"),b),V(r,"".concat(p,"-textarea-allow-clear"),c),r))}),disabled:x,focused:O,className:te(y,re&&"".concat(p,"-out-of-range")),style:U(U({},S),k&&!ke?{height:"auto"}:{}),dataAttrs:{affixWrapper:{"data-count":typeof xe=="string"?xe:void 0}},hidden:$,children:C(h7,{...P,maxLength:u,onKeyDown:se,onChange:oe,onFocus:le,onBlur:Ce,onCompositionStart:ve,onCompositionEnd:pe,className:te(E==null?void 0:E.textarea),style:U(U({},w==null?void 0:w.textarea),{},{resize:S==null?void 0:S.resize}),disabled:x,prefixCls:p,onResize:he,ref:H})})}),b7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n;const{prefixCls:r,bordered:o=!0,size:i,disabled:a,status:l,allowClear:s,classNames:c,rootClassName:u,className:d,variant:v}=e,h=b7(e,["prefixCls","bordered","size","disabled","status","allowClear","classNames","rootClassName","className","variant"]),{getPrefixCls:g,direction:p}=f.exports.useContext(ot),b=So(i),m=f.exports.useContext(rl),y=a!=null?a:m,{status:S,hasFeedback:x,feedbackIcon:$}=f.exports.useContext(Jr),E=dm(S,l),w=f.exports.useRef(null);f.exports.useImperativeHandle(t,()=>{var _;return{resizableTextArea:(_=w.current)===null||_===void 0?void 0:_.resizableTextArea,focus:O=>{var M,L;t7((L=(M=w.current)===null||M===void 0?void 0:M.resizableTextArea)===null||L===void 0?void 0:L.textArea,O)},blur:()=>{var O;return(O=w.current)===null||O===void 0?void 0:O.blur()}}});const R=g("input",r);let P;typeof s=="object"&&(s==null?void 0:s.clearIcon)?P=s:s&&(P={clearIcon:C(Nd,{})});const N=no(R),[I,z,F]=Im(R,N),[T,D]=vm(v,o);return I(C(y7,{...Object.assign({},h,{disabled:y,allowClear:P,className:te(F,N,d,u),classNames:Object.assign(Object.assign({},c),{textarea:te({[`${R}-sm`]:b==="small",[`${R}-lg`]:b==="large"},z,c==null?void 0:c.textarea),variant:te({[`${R}-${T}`]:D},ed(R,E)),affixWrapper:te(`${R}-textarea-affix-wrapper`,{[`${R}-affix-wrapper-rtl`]:p==="rtl",[`${R}-affix-wrapper-sm`]:b==="small",[`${R}-affix-wrapper-lg`]:b==="large",[`${R}-textarea-show-count`]:e.showCount||((n=e.count)===null||n===void 0?void 0:n.show)},z)}),prefixCls:R,suffix:x&&C("span",{className:`${R}-textarea-suffix`,children:$}),ref:w})}))}),C7=S7,Js=Tm;Js.Group=Xk;Js.Search=u7;Js.TextArea=C7;Js.Password=l7;const C$=Js;function x$(){var e=document.documentElement.clientWidth,t=window.innerHeight||document.documentElement.clientHeight;return{width:e,height:t}}function x7(e){var t=e.getBoundingClientRect(),n=document.documentElement;return{left:t.left+(window.pageXOffset||n.scrollLeft)-(n.clientLeft||document.body.clientLeft||0),top:t.top+(window.pageYOffset||n.scrollTop)-(n.clientTop||document.body.clientTop||0)}}var Pg=["crossOrigin","decoding","draggable","loading","referrerPolicy","sizes","srcSet","useMap","alt"],ec=f.exports.createContext(null),a1=0;function w7(e,t){var n=f.exports.useState(function(){return a1+=1,String(a1)}),r=G(n,1),o=r[0],i=f.exports.useContext(ec),a={data:t,canPreview:e};return f.exports.useEffect(function(){if(i)return i.register(o,a)},[]),f.exports.useEffect(function(){i&&i.register(o,a)},[e,t]),o}function $7(e){return new Promise(function(t){var n=document.createElement("img");n.onerror=function(){return t(!1)},n.onload=function(){return t(!0)},n.src=e})}function w$(e){var t=e.src,n=e.isCustomPlaceholder,r=e.fallback,o=f.exports.useState(n?"loading":"normal"),i=G(o,2),a=i[0],l=i[1],s=f.exports.useRef(!1),c=a==="error";f.exports.useEffect(function(){var h=!0;return $7(t).then(function(g){!g&&h&&l("error")}),function(){h=!1}},[t]),f.exports.useEffect(function(){n&&!s.current?l("loading"):c&&l("normal")},[t]);var u=function(){l("normal")},d=function(g){s.current=!1,a==="loading"&&g!==null&&g!==void 0&&g.complete&&(g.naturalWidth||g.naturalHeight)&&(s.current=!0,u())},v=c&&r?{src:r}:{onLoad:u,src:t};return[d,v,a]}function $a(e,t,n,r){var o=zu.unstable_batchedUpdates?function(a){zu.unstable_batchedUpdates(n,a)}:n;return e!=null&&e.addEventListener&&e.addEventListener(t,o,r),{remove:function(){e!=null&&e.removeEventListener&&e.removeEventListener(t,o,r)}}}var kc={x:0,y:0,rotate:0,scale:1,flipX:!1,flipY:!1};function E7(e,t,n,r){var o=f.exports.useRef(null),i=f.exports.useRef([]),a=f.exports.useState(kc),l=G(a,2),s=l[0],c=l[1],u=function(g){c(kc),r&&!Vs(kc,s)&&r({transform:kc,action:g})},d=function(g,p){o.current===null&&(i.current=[],o.current=St(function(){c(function(b){var m=b;return i.current.forEach(function(y){m=U(U({},m),y)}),o.current=null,r==null||r({transform:m,action:p}),m})})),i.current.push(U(U({},s),g))},v=function(g,p,b,m,y){var S=e.current,x=S.width,$=S.height,E=S.offsetWidth,w=S.offsetHeight,R=S.offsetLeft,P=S.offsetTop,N=g,I=s.scale*g;I>n?(I=n,N=n/s.scale):Ir){if(t>0)return V({},e,i);if(t<0&&or)return V({},e,t<0?i:-i);return{}}function $$(e,t,n,r){var o=x$(),i=o.width,a=o.height,l=null;return e<=i&&t<=a?l={x:0,y:0}:(e>i||t>a)&&(l=U(U({},l1("x",n,e,i)),l1("y",r,t,a))),l}var Ea=1,M7=1;function O7(e,t,n,r,o,i,a){var l=o.rotate,s=o.scale,c=o.x,u=o.y,d=f.exports.useState(!1),v=G(d,2),h=v[0],g=v[1],p=f.exports.useRef({diffX:0,diffY:0,transformX:0,transformY:0}),b=function($){!t||$.button!==0||($.preventDefault(),$.stopPropagation(),p.current={diffX:$.pageX-c,diffY:$.pageY-u,transformX:c,transformY:u},g(!0))},m=function($){n&&h&&i({x:$.pageX-p.current.diffX,y:$.pageY-p.current.diffY},"move")},y=function(){if(n&&h){g(!1);var $=p.current,E=$.transformX,w=$.transformY,R=c!==E&&u!==w;if(!R)return;var P=e.current.offsetWidth*s,N=e.current.offsetHeight*s,I=e.current.getBoundingClientRect(),z=I.left,F=I.top,T=l%180!==0,D=$$(T?N:P,T?P:N,z,F);D&&i(U({},D),"dragRebound")}},S=function($){if(!(!n||$.deltaY==0)){var E=Math.abs($.deltaY/100),w=Math.min(E,M7),R=Ea+w*r;$.deltaY>0&&(R=Ea/R),a(R,"wheel",$.clientX,$.clientY)}};return f.exports.useEffect(function(){var x,$,E,w;if(t){E=$a(window,"mouseup",y,!1),w=$a(window,"mousemove",m,!1);try{window.top!==window.self&&(x=$a(window.top,"mouseup",y,!1),$=$a(window.top,"mousemove",m,!1))}catch{}}return function(){var R,P,N,I;(R=E)===null||R===void 0||R.remove(),(P=w)===null||P===void 0||P.remove(),(N=x)===null||N===void 0||N.remove(),(I=$)===null||I===void 0||I.remove()}},[n,h,c,u,l,t]),{isMoving:h,onMouseDown:b,onMouseMove:m,onMouseUp:y,onWheel:S}}function id(e,t){var n=e.x-t.x,r=e.y-t.y;return Math.hypot(n,r)}function R7(e,t,n,r){var o=id(e,n),i=id(t,r);if(o===0&&i===0)return[e.x,e.y];var a=o/(o+i),l=e.x+a*(t.x-e.x),s=e.y+a*(t.y-e.y);return[l,s]}function I7(e,t,n,r,o,i,a){var l=o.rotate,s=o.scale,c=o.x,u=o.y,d=f.exports.useState(!1),v=G(d,2),h=v[0],g=v[1],p=f.exports.useRef({point1:{x:0,y:0},point2:{x:0,y:0},eventType:"none"}),b=function($){p.current=U(U({},p.current),$)},m=function($){if(!!t){$.stopPropagation(),g(!0);var E=$.touches,w=E===void 0?[]:E;w.length>1?b({point1:{x:w[0].clientX,y:w[0].clientY},point2:{x:w[1].clientX,y:w[1].clientY},eventType:"touchZoom"}):b({point1:{x:w[0].clientX-c,y:w[0].clientY-u},eventType:"move"})}},y=function($){var E=$.touches,w=E===void 0?[]:E,R=p.current,P=R.point1,N=R.point2,I=R.eventType;if(w.length>1&&I==="touchZoom"){var z={x:w[0].clientX,y:w[0].clientY},F={x:w[1].clientX,y:w[1].clientY},T=R7(P,N,z,F),D=G(T,2),_=D[0],O=D[1],M=id(z,F)/id(P,N);a(M,"touchZoom",_,O,!0),b({point1:z,point2:F,eventType:"touchZoom"})}else I==="move"&&(i({x:w[0].clientX-P.x,y:w[0].clientY-P.y},"move"),b({eventType:"move"}))},S=function(){if(!!n){if(h&&g(!1),b({eventType:"none"}),r>s)return i({x:0,y:0,scale:r},"touchZoom");var $=e.current.offsetWidth*s,E=e.current.offsetHeight*s,w=e.current.getBoundingClientRect(),R=w.left,P=w.top,N=l%180!==0,I=$$(N?E:$,N?$:E,R,P);I&&i(U({},I),"dragRebound")}};return f.exports.useEffect(function(){var x;return n&&t&&(x=$a(window,"touchmove",function($){return $.preventDefault()},{passive:!1})),function(){var $;($=x)===null||$===void 0||$.remove()}},[n,t]),{isTouching:h,onTouchStart:m,onTouchMove:y,onTouchEnd:S}}var P7=function(t){var n=t.visible,r=t.maskTransitionName,o=t.getContainer,i=t.prefixCls,a=t.rootClassName,l=t.icons,s=t.countRender,c=t.showSwitch,u=t.showProgress,d=t.current,v=t.transform,h=t.count,g=t.scale,p=t.minScale,b=t.maxScale,m=t.closeIcon,y=t.onSwitchLeft,S=t.onSwitchRight,x=t.onClose,$=t.onZoomIn,E=t.onZoomOut,w=t.onRotateRight,R=t.onRotateLeft,P=t.onFlipX,N=t.onFlipY,I=t.toolbarRender,z=t.zIndex,F=f.exports.useContext(ec),T=l.rotateLeft,D=l.rotateRight,_=l.zoomIn,O=l.zoomOut,M=l.close,L=l.left,A=l.right,B=l.flipX,k=l.flipY,j="".concat(i,"-operations-operation");f.exports.useEffect(function(){var K=function(ee){ee.keyCode===ue.ESC&&x()};return n&&window.addEventListener("keydown",K),function(){window.removeEventListener("keydown",K)}},[n]);var H=[{icon:k,onClick:N,type:"flipY"},{icon:B,onClick:P,type:"flipX"},{icon:T,onClick:R,type:"rotateLeft"},{icon:D,onClick:w,type:"rotateRight"},{icon:O,onClick:E,type:"zoomOut",disabled:g<=p},{icon:_,onClick:$,type:"zoomIn",disabled:g===b}],W=H.map(function(K){var q,ee=K.icon,Z=K.onClick,Q=K.type,ne=K.disabled;return C("div",{className:te(j,(q={},V(q,"".concat(i,"-operations-operation-").concat(Q),!0),V(q,"".concat(i,"-operations-operation-disabled"),!!ne),q)),onClick:Z,children:ee},Q)}),Y=C("div",{className:"".concat(i,"-operations"),children:W});return C(to,{visible:n,motionName:r,children:function(K){var q=K.className,ee=K.style;return C(nf,{open:!0,getContainer:o!=null?o:document.body,children:ie("div",{className:te("".concat(i,"-operations-wrapper"),q,a),style:U(U({},ee),{},{zIndex:z}),children:[m===null?null:C("button",{className:"".concat(i,"-close"),onClick:x,children:m||M}),c&&ie(Tt,{children:[C("div",{className:te("".concat(i,"-switch-left"),V({},"".concat(i,"-switch-left-disabled"),d===0)),onClick:y,children:L}),C("div",{className:te("".concat(i,"-switch-right"),V({},"".concat(i,"-switch-right-disabled"),d===h-1)),onClick:S,children:A})]}),ie("div",{className:"".concat(i,"-footer"),children:[u&&C("div",{className:"".concat(i,"-progress"),children:s?s(d+1,h):"".concat(d+1," / ").concat(h)}),I?I(Y,U({icons:{flipYIcon:W[0],flipXIcon:W[1],rotateLeftIcon:W[2],rotateRightIcon:W[3],zoomOutIcon:W[4],zoomInIcon:W[5]},actions:{onFlipY:N,onFlipX:P,onRotateLeft:R,onRotateRight:w,onZoomOut:E,onZoomIn:$},transform:v},F?{current:d,total:h}:{})):Y]})]})})}})},T7=["fallback","src","imgRef"],N7=["prefixCls","src","alt","fallback","movable","onClose","visible","icons","rootClassName","closeIcon","getContainer","current","count","countRender","scaleStep","minScale","maxScale","transitionName","maskTransitionName","imageRender","imgCommonProps","toolbarRender","onTransform","onChange"],_7=function(t){var n=t.fallback,r=t.src,o=t.imgRef,i=Je(t,T7),a=w$({src:r,fallback:n}),l=G(a,2),s=l[0],c=l[1];return C("img",{ref:function(d){o.current=d,s(d)},...i,...c})},E$=function(t){var n=t.prefixCls,r=t.src,o=t.alt,i=t.fallback,a=t.movable,l=a===void 0?!0:a,s=t.onClose,c=t.visible,u=t.icons,d=u===void 0?{}:u,v=t.rootClassName,h=t.closeIcon,g=t.getContainer,p=t.current,b=p===void 0?0:p,m=t.count,y=m===void 0?1:m,S=t.countRender,x=t.scaleStep,$=x===void 0?.5:x,E=t.minScale,w=E===void 0?1:E,R=t.maxScale,P=R===void 0?50:R,N=t.transitionName,I=N===void 0?"zoom":N,z=t.maskTransitionName,F=z===void 0?"fade":z,T=t.imageRender,D=t.imgCommonProps,_=t.toolbarRender,O=t.onTransform,M=t.onChange,L=Je(t,N7),A=f.exports.useRef(),B=f.exports.useContext(ec),k=B&&y>1,j=B&&y>=1,H=f.exports.useState(!0),W=G(H,2),Y=W[0],K=W[1],q=E7(A,w,P,O),ee=q.transform,Z=q.resetTransform,Q=q.updateTransform,ne=q.dispatchZoomChange,ae=O7(A,l,c,$,ee,Q,ne),J=ae.isMoving,re=ae.onMouseDown,fe=ae.onWheel,ve=I7(A,l,c,w,ee,Q,ne),pe=ve.isTouching,oe=ve.onTouchStart,se=ve.onTouchMove,le=ve.onTouchEnd,Ce=ee.rotate,ce=ee.scale,de=te(V({},"".concat(n,"-moving"),J));f.exports.useEffect(function(){Y||K(!0)},[Y]);var xe=function(){Z("close")},he=function(){ne(Ea+$,"zoomIn")},ke=function(){ne(Ea/(Ea+$),"zoomOut")},we=function(){Q({rotate:Ce+90},"rotateRight")},ge=function(){Q({rotate:Ce-90},"rotateLeft")},Pe=function(){Q({flipX:!ee.flipX},"flipX")},Se=function(){Q({flipY:!ee.flipY},"flipY")},st=function(qe){qe==null||qe.preventDefault(),qe==null||qe.stopPropagation(),b>0&&(K(!1),Z("prev"),M==null||M(b-1,b))},nt=function(qe){qe==null||qe.preventDefault(),qe==null||qe.stopPropagation(),b({position:e||"absolute",inset:0}),B7=e=>{const{iconCls:t,motionDurationSlow:n,paddingXXS:r,marginXXS:o,prefixCls:i,colorTextLightSolid:a}=e;return{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",color:a,background:new Mt("#000").setAlpha(.5).toRgbString(),cursor:"pointer",opacity:0,transition:`opacity ${n}`,[`.${i}-mask-info`]:Object.assign(Object.assign({},ei),{padding:`0 ${X(r)}`,[t]:{marginInlineEnd:o,svg:{verticalAlign:"baseline"}}})}},j7=e=>{const{previewCls:t,modalMaskBg:n,paddingSM:r,marginXL:o,margin:i,paddingLG:a,previewOperationColorDisabled:l,previewOperationHoverColor:s,motionDurationSlow:c,iconCls:u,colorTextLightSolid:d}=e,v=new Mt(n).setAlpha(.1),h=v.clone().setAlpha(.2);return{[`${t}-footer`]:{position:"fixed",bottom:o,left:{_skip_check_:!0,value:0},width:"100%",display:"flex",flexDirection:"column",alignItems:"center",color:e.previewOperationColor},[`${t}-progress`]:{marginBottom:i},[`${t}-close`]:{position:"fixed",top:o,right:{_skip_check_:!0,value:o},display:"flex",color:d,backgroundColor:v.toRgbString(),borderRadius:"50%",padding:r,outline:0,border:0,cursor:"pointer",transition:`all ${c}`,"&:hover":{backgroundColor:h.toRgbString()},[`& > ${u}`]:{fontSize:e.previewOperationSize}},[`${t}-operations`]:{display:"flex",alignItems:"center",padding:`0 ${X(a)}`,backgroundColor:v.toRgbString(),borderRadius:100,"&-operation":{marginInlineStart:r,padding:r,cursor:"pointer",transition:`all ${c}`,userSelect:"none",[`&:not(${t}-operations-operation-disabled):hover > ${u}`]:{color:s},"&-disabled":{color:l,cursor:"not-allowed"},"&:first-of-type":{marginInlineStart:0},[`& > ${u}`]:{fontSize:e.previewOperationSize}}}}},H7=e=>{const{modalMaskBg:t,iconCls:n,previewOperationColorDisabled:r,previewCls:o,zIndexPopup:i,motionDurationSlow:a}=e,l=new Mt(t).setAlpha(.1),s=l.clone().setAlpha(.2);return{[`${o}-switch-left, ${o}-switch-right`]:{position:"fixed",insetBlockStart:"50%",zIndex:e.calc(i).add(1).equal({unit:!1}),display:"flex",alignItems:"center",justifyContent:"center",width:e.imagePreviewSwitchSize,height:e.imagePreviewSwitchSize,marginTop:e.calc(e.imagePreviewSwitchSize).mul(-1).div(2).equal(),color:e.previewOperationColor,background:l.toRgbString(),borderRadius:"50%",transform:"translateY(-50%)",cursor:"pointer",transition:`all ${a}`,userSelect:"none","&:hover":{background:s.toRgbString()},["&-disabled"]:{"&, &:hover":{color:r,background:"transparent",cursor:"not-allowed",[`> ${n}`]:{cursor:"not-allowed"}}},[`> ${n}`]:{fontSize:e.previewOperationSize}},[`${o}-switch-left`]:{insetInlineStart:e.marginSM},[`${o}-switch-right`]:{insetInlineEnd:e.marginSM}}},W7=e=>{const{motionEaseOut:t,previewCls:n,motionDurationSlow:r,componentCls:o}=e;return[{[`${o}-preview-root`]:{[n]:{height:"100%",textAlign:"center",pointerEvents:"none"},[`${n}-body`]:Object.assign(Object.assign({},Tg()),{overflow:"hidden"}),[`${n}-img`]:{maxWidth:"100%",maxHeight:"70%",verticalAlign:"middle",transform:"scale3d(1, 1, 1)",cursor:"grab",transition:`transform ${r} ${t} 0s`,userSelect:"none","&-wrapper":Object.assign(Object.assign({},Tg()),{transition:`transform ${r} ${t} 0s`,display:"flex",justifyContent:"center",alignItems:"center","& > *":{pointerEvents:"auto"},"&::before":{display:"inline-block",width:1,height:"50%",marginInlineEnd:-1,content:'""'}})},[`${n}-moving`]:{[`${n}-preview-img`]:{cursor:"grabbing","&-wrapper":{transitionDuration:"0s"}}}}},{[`${o}-preview-root`]:{[`${n}-wrap`]:{zIndex:e.zIndexPopup}}},{[`${o}-preview-operations-wrapper`]:{position:"fixed",zIndex:e.calc(e.zIndexPopup).add(1).equal({unit:!1})},"&":[j7(e),H7(e)]}]},V7=e=>{const{componentCls:t}=e;return{[t]:{position:"relative",display:"inline-block",[`${t}-img`]:{width:"100%",height:"auto",verticalAlign:"middle"},[`${t}-img-placeholder`]:{backgroundColor:e.colorBgContainerDisabled,backgroundImage:"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuNSAyLjVoLTEzQS41LjUgMCAwIDAgMSAzdjEwYS41LjUgMCAwIDAgLjUuNWgxM2EuNS41IDAgMCAwIC41LS41VjNhLjUuNSAwIDAgMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwIDEgMCAyIDEgMSAwIDAgMSAwLTJ6bTguMDMgNi44M2EuMTI3LjEyNyAwIDAgMS0uMDgxLjAzSDIuNzY5YS4xMjUuMTI1IDAgMCAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAgMSAuMTc3LS4wMTZsLjAxNi4wMTZMNy4wOCAxMC4wOWwyLjQ3LTIuOTNhLjEyNi4xMjYgMCAwIDEgLjE3Ny0uMDE2bC4wMTUuMDE2IDMuNTg4IDQuMjQ0YS4xMjcuMTI3IDAgMCAxLS4wMi4xNzV6IiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=')",backgroundRepeat:"no-repeat",backgroundPosition:"center center",backgroundSize:"30%"},[`${t}-mask`]:Object.assign({},B7(e)),[`${t}-mask:hover`]:{opacity:1},[`${t}-placeholder`]:Object.assign({},Tg())}}},U7=e=>{const{previewCls:t}=e;return{[`${t}-root`]:of(e,"zoom"),["&"]:zw(e,!0)}},Y7=e=>({zIndexPopup:e.zIndexPopupBase+80,previewOperationColor:new Mt(e.colorTextLightSolid).setAlpha(.65).toRgbString(),previewOperationHoverColor:new Mt(e.colorTextLightSolid).setAlpha(.85).toRgbString(),previewOperationColorDisabled:new Mt(e.colorTextLightSolid).setAlpha(.25).toRgbString(),previewOperationSize:e.fontSizeIcon*1.5}),M$=vn("Image",e=>{const t=`${e.componentCls}-preview`,n=$t(e,{previewCls:t,modalMaskBg:new Mt("#000").setAlpha(.45).toRgbString(),imagePreviewSwitchSize:e.controlHeightLG});return[V7(n),W7(n),Fw($t(n,{componentCls:t})),U7(n)]},Y7);var G7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var{previewPrefixCls:t,preview:n}=e,r=G7(e,["previewPrefixCls","preview"]);const{getPrefixCls:o}=f.exports.useContext(ot),i=o("image",t),a=`${i}-preview`,l=o(),s=no(i),[c,u,d]=M$(i,s),[v]=Qd("ImagePreview",typeof n=="object"?n.zIndex:void 0),h=f.exports.useMemo(()=>{var g;if(n===!1)return n;const p=typeof n=="object"?n:{},b=te(u,d,s,(g=p.rootClassName)!==null&&g!==void 0?g:"");return Object.assign(Object.assign({},p),{transitionName:ni(l,"zoom",p.transitionName),maskTransitionName:ni(l,"fade",p.maskTransitionName),rootClassName:b,zIndex:v})},[n]);return c(C(hf.PreviewGroup,{...Object.assign({preview:h,previewPrefixCls:a,icons:O$},r)}))},q7=K7;var s1=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var t;const{prefixCls:n,preview:r,className:o,rootClassName:i,style:a}=e,l=s1(e,["prefixCls","preview","className","rootClassName","style"]),{getPrefixCls:s,locale:c=Jo,getPopupContainer:u,image:d}=f.exports.useContext(ot),v=s("image",n),h=s(),g=c.Image||Jo.Image,p=no(v),[b,m,y]=M$(v,p),S=te(i,m,y,p),x=te(o,m,d==null?void 0:d.className),[$]=Qd("ImagePreview",typeof r=="object"?r.zIndex:void 0),E=f.exports.useMemo(()=>{var R;if(r===!1)return r;const P=typeof r=="object"?r:{},{getContainer:N,closeIcon:I}=P,z=s1(P,["getContainer","closeIcon"]);return Object.assign(Object.assign({mask:ie("div",{className:`${v}-mask-info`,children:[C(sx,{}),g==null?void 0:g.preview]}),icons:O$},z),{getContainer:N!=null?N:u,transitionName:ni(h,"zoom",P.transitionName),maskTransitionName:ni(h,"fade",P.maskTransitionName),zIndex:$,closeIcon:I!=null?I:(R=d==null?void 0:d.preview)===null||R===void 0?void 0:R.closeIcon})},[r,g,(t=d==null?void 0:d.preview)===null||t===void 0?void 0:t.closeIcon]),w=Object.assign(Object.assign({},d==null?void 0:d.style),a);return b(C(hf,{...Object.assign({prefixCls:v,preview:E,rootClassName:S,className:x,style:w},l)}))};R$.PreviewGroup=q7;const cu=R$,X7=new Ct("antSpinMove",{to:{opacity:1}}),Q7=new Ct("antRotate",{to:{transform:"rotate(405deg)"}}),Z7=e=>{const{componentCls:t,calc:n}=e;return{[`${t}`]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",display:"none",color:e.colorPrimary,fontSize:0,textAlign:"center",verticalAlign:"middle",opacity:0,transition:`transform ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`,"&-spinning":{position:"static",display:"inline-block",opacity:1},[`${t}-text`]:{fontSize:e.fontSize,paddingTop:n(n(e.dotSize).sub(e.fontSize)).div(2).add(2).equal()},"&-fullscreen":{position:"fixed",width:"100vw",height:"100vh",backgroundColor:e.colorBgMask,zIndex:e.zIndexPopupBase,inset:0,display:"flex",alignItems:"center",flexDirection:"column",justifyContent:"center",opacity:0,visibility:"hidden",transition:`all ${e.motionDurationMid}`,"&-show":{opacity:1,visibility:"visible"},[`${t}-dot ${t}-dot-item`]:{backgroundColor:e.colorWhite},[`${t}-text`]:{color:e.colorTextLightSolid}},"&-nested-loading":{position:"relative",[`> div > ${t}`]:{position:"absolute",top:0,insetInlineStart:0,zIndex:4,display:"block",width:"100%",height:"100%",maxHeight:e.contentHeight,[`${t}-dot`]:{position:"absolute",top:"50%",insetInlineStart:"50%",margin:n(e.dotSize).mul(-1).div(2).equal()},[`${t}-text`]:{position:"absolute",top:"50%",width:"100%",textShadow:`0 1px 2px ${e.colorBgContainer}`},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSize).div(2).mul(-1).sub(10).equal()},"&-sm":{[`${t}-dot`]:{margin:n(e.dotSizeSM).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:n(n(e.dotSizeSM).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSizeSM).div(2).mul(-1).sub(10).equal()}},"&-lg":{[`${t}-dot`]:{margin:n(e.dotSizeLG).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:n(n(e.dotSizeLG).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSizeLG).div(2).mul(-1).sub(10).equal()}}},[`${t}-container`]:{position:"relative",transition:`opacity ${e.motionDurationSlow}`,"&::after":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:10,width:"100%",height:"100%",background:e.colorBgContainer,opacity:0,transition:`all ${e.motionDurationSlow}`,content:'""',pointerEvents:"none"}},[`${t}-blur`]:{clear:"both",opacity:.5,userSelect:"none",pointerEvents:"none",["&::after"]:{opacity:.4,pointerEvents:"auto"}}},["&-tip"]:{color:e.spinDotDefault},[`${t}-dot`]:{position:"relative",display:"inline-block",fontSize:e.dotSize,width:"1em",height:"1em","&-item":{position:"absolute",display:"block",width:n(e.dotSize).sub(n(e.marginXXS).div(2)).div(2).equal(),height:n(e.dotSize).sub(n(e.marginXXS).div(2)).div(2).equal(),backgroundColor:e.colorPrimary,borderRadius:"100%",transform:"scale(0.75)",transformOrigin:"50% 50%",opacity:.3,animationName:X7,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear",animationDirection:"alternate","&:nth-child(1)":{top:0,insetInlineStart:0,animationDelay:"0s"},"&:nth-child(2)":{top:0,insetInlineEnd:0,animationDelay:"0.4s"},"&:nth-child(3)":{insetInlineEnd:0,bottom:0,animationDelay:"0.8s"},"&:nth-child(4)":{bottom:0,insetInlineStart:0,animationDelay:"1.2s"}},"&-spin":{transform:"rotate(45deg)",animationName:Q7,animationDuration:"1.2s",animationIterationCount:"infinite",animationTimingFunction:"linear"}},[`&-sm ${t}-dot`]:{fontSize:e.dotSizeSM,i:{width:n(n(e.dotSizeSM).sub(n(e.marginXXS).div(2))).div(2).equal(),height:n(n(e.dotSizeSM).sub(n(e.marginXXS).div(2))).div(2).equal()}},[`&-lg ${t}-dot`]:{fontSize:e.dotSizeLG,i:{width:n(n(e.dotSizeLG).sub(e.marginXXS)).div(2).equal(),height:n(n(e.dotSizeLG).sub(e.marginXXS)).div(2).equal()}},[`&${t}-show-text ${t}-text`]:{display:"block"}})}},J7=e=>{const{controlHeightLG:t,controlHeight:n}=e;return{contentHeight:400,dotSize:t/2,dotSizeSM:t*.35,dotSizeLG:n}},eB=vn("Spin",e=>{const t=$t(e,{spinDotDefault:e.colorTextDescription});return[Z7(t)]},J7);var tB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:t,spinning:n=!0,delay:r=0,className:o,rootClassName:i,size:a="default",tip:l,wrapperClassName:s,style:c,children:u,fullscreen:d=!1}=e,v=tB(e,["prefixCls","spinning","delay","className","rootClassName","size","tip","wrapperClassName","style","children","fullscreen"]),{getPrefixCls:h}=f.exports.useContext(ot),g=h("spin",t),[p,b,m]=eB(g),[y,S]=f.exports.useState(()=>n&&!rB(n,r));f.exports.useEffect(()=>{if(n){const z=Hk(r,()=>{S(!0)});return z(),()=>{var F;(F=z==null?void 0:z.cancel)===null||F===void 0||F.call(z)}}S(!1)},[r,n]);const x=f.exports.useMemo(()=>typeof u<"u"&&!d,[u,d]),{direction:$,spin:E}=f.exports.useContext(ot),w=te(g,E==null?void 0:E.className,{[`${g}-sm`]:a==="small",[`${g}-lg`]:a==="large",[`${g}-spinning`]:y,[`${g}-show-text`]:!!l,[`${g}-fullscreen`]:d,[`${g}-fullscreen-show`]:d&&y,[`${g}-rtl`]:$==="rtl"},o,i,b,m),R=te(`${g}-container`,{[`${g}-blur`]:y}),P=lr(v,["indicator"]),N=Object.assign(Object.assign({},E==null?void 0:E.style),c),I=ie("div",{...Object.assign({},P,{style:N,className:w,"aria-live":"polite","aria-busy":y}),children:[nB(g,e),l&&(x||d)?C("div",{className:`${g}-text`,children:l}):null]});return p(x?ie("div",{...Object.assign({},P,{className:te(`${g}-nested-loading`,s,b,m)}),children:[y&&C("div",{children:I},"loading"),C("div",{className:R,children:u},"container")]}):I)};I$.setDefaultIndicator=e=>{uu=e};const oB=I$;var iB={percent:0,prefixCls:"rc-progress",strokeColor:"#2db7f5",strokeLinecap:"round",strokeWidth:1,trailColor:"#D9D9D9",trailWidth:1,gapPosition:"bottom"},aB=function(){var t=f.exports.useRef([]),n=f.exports.useRef(null);return f.exports.useEffect(function(){var r=Date.now(),o=!1;t.current.forEach(function(i){if(!!i){o=!0;var a=i.style;a.transitionDuration=".3s, .3s, .3s, .06s",n.current&&r-n.current<100&&(a.transitionDuration="0s, 0s")}}),o&&(n.current=Date.now())}),t.current},c1=0,lB=Rn();function sB(){var e;return lB?(e=c1,c1+=1):e="TEST_OR_SSR",e}const cB=function(e){var t=f.exports.useState(),n=G(t,2),r=n[0],o=n[1];return f.exports.useEffect(function(){o("rc_progress_".concat(sB()))},[]),e||r};var u1=function(t){var n=t.bg,r=t.children;return C("div",{style:{width:"100%",height:"100%",background:n},children:r})};function d1(e,t){return Object.keys(e).map(function(n){var r=parseFloat(n),o="".concat(Math.floor(r*t),"%");return"".concat(e[n]," ").concat(o)})}var uB=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.color,o=e.gradientId,i=e.radius,a=e.style,l=e.ptg,s=e.strokeLinecap,c=e.strokeWidth,u=e.size,d=e.gapDegree,v=r&&Qe(r)==="object",h=v?"#FFF":void 0,g=u/2,p=C("circle",{className:"".concat(n,"-circle-path"),r:i,cx:g,cy:g,stroke:h,strokeLinecap:s,strokeWidth:c,opacity:l===0?0:1,style:a,ref:t});if(!v)return p;var b="".concat(o,"-conic"),m=d?"".concat(180+d/2,"deg"):"0deg",y=d1(r,(360-d)/360),S=d1(r,1),x="conic-gradient(from ".concat(m,", ").concat(y.join(", "),")"),$="linear-gradient(to ".concat(d?"bottom":"top",", ").concat(S.join(", "),")");return ie(Tt,{children:[C("mask",{id:b,children:p}),C("foreignObject",{x:0,y:0,width:u,height:u,mask:"url(#".concat(b,")"),children:C(u1,{bg:$,children:C(u1,{bg:x})})})]})}),Dl=100,Iv=function(t,n,r,o,i,a,l,s,c,u){var d=arguments.length>10&&arguments[10]!==void 0?arguments[10]:0,v=r/100*360*((360-a)/360),h=a===0?0:{bottom:0,top:180,left:90,right:-90}[l],g=(100-o)/100*n;c==="round"&&o!==100&&(g+=u/2,g>=n&&(g=n-.01));var p=Dl/2;return{stroke:typeof s=="string"?s:void 0,strokeDasharray:"".concat(n,"px ").concat(t),strokeDashoffset:g+d,transform:"rotate(".concat(i+v+h,"deg)"),transformOrigin:"".concat(p,"px ").concat(p,"px"),transition:"stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s",fillOpacity:0}},dB=["id","prefixCls","steps","strokeWidth","trailWidth","gapDegree","gapPosition","trailColor","strokeLinecap","style","className","strokeColor","percent"];function f1(e){var t=e!=null?e:[];return Array.isArray(t)?t:[t]}var fB=function(t){var n=U(U({},iB),t),r=n.id,o=n.prefixCls,i=n.steps,a=n.strokeWidth,l=n.trailWidth,s=n.gapDegree,c=s===void 0?0:s,u=n.gapPosition,d=n.trailColor,v=n.strokeLinecap,h=n.style,g=n.className,p=n.strokeColor,b=n.percent,m=Je(n,dB),y=Dl/2,S=cB(r),x="".concat(S,"-gradient"),$=y-a/2,E=Math.PI*2*$,w=c>0?90+c/2:-90,R=E*((360-c)/360),P=Qe(i)==="object"?i:{count:i,space:2},N=P.count,I=P.space,z=f1(b),F=f1(p),T=F.find(function(B){return B&&Qe(B)==="object"}),D=T&&Qe(T)==="object",_=D?"butt":v,O=Iv(E,R,0,100,w,c,u,d,_,a),M=aB(),L=function(){var k=0;return z.map(function(j,H){var W=F[H]||F[F.length-1],Y=Iv(E,R,k,j,w,c,u,W,_,a);return k+=j,C(uB,{color:W,ptg:j,radius:$,prefixCls:o,gradientId:x,style:Y,strokeLinecap:_,strokeWidth:a,gapDegree:c,ref:function(q){M[H]=q},size:Dl},H)}).reverse()},A=function(){var k=Math.round(N*(z[0]/100)),j=100/N,H=0;return new Array(N).fill(null).map(function(W,Y){var K=Y<=k-1?F[0]:d,q=K&&Qe(K)==="object"?"url(#".concat(x,")"):void 0,ee=Iv(E,R,H,j,w,c,u,K,"butt",a,I);return H+=(R-ee.strokeDashoffset+I)*100/R,C("circle",{className:"".concat(o,"-circle-path"),r:$,cx:y,cy:y,stroke:q,strokeWidth:a,opacity:1,style:ee,ref:function(Q){M[Y]=Q}},Y)})};return ie("svg",{className:te("".concat(o,"-circle"),g),viewBox:"0 0 ".concat(Dl," ").concat(Dl),style:h,id:r,role:"presentation",...m,children:[!N&&C("circle",{className:"".concat(o,"-circle-trail"),r:$,cx:y,cy:y,stroke:d,strokeLinecap:_,strokeWidth:l||a,style:O}),N?A():L()]})};function Go(e){return!e||e<0?0:e>100?100:e}function ad(e){let{success:t,successPercent:n}=e,r=n;return t&&"progress"in t&&(r=t.progress),t&&"percent"in t&&(r=t.percent),r}const vB=e=>{let{percent:t,success:n,successPercent:r}=e;const o=Go(ad({success:n,successPercent:r}));return[o,Go(Go(t)-o)]},pB=e=>{let{success:t={},strokeColor:n}=e;const{strokeColor:r}=t;return[r||Na.green,n||null]},mf=(e,t,n)=>{var r,o,i,a;let l=-1,s=-1;if(t==="step"){const c=n.steps,u=n.strokeWidth;typeof e=="string"||typeof e>"u"?(l=e==="small"?2:14,s=u!=null?u:8):typeof e=="number"?[l,s]=[e,e]:[l=14,s=8]=e,l*=c}else if(t==="line"){const c=n==null?void 0:n.strokeWidth;typeof e=="string"||typeof e>"u"?s=c||(e==="small"?6:8):typeof e=="number"?[l,s]=[e,e]:[l=-1,s=8]=e}else(t==="circle"||t==="dashboard")&&(typeof e=="string"||typeof e>"u"?[l,s]=e==="small"?[60,60]:[120,120]:typeof e=="number"?[l,s]=[e,e]:(l=(o=(r=e[0])!==null&&r!==void 0?r:e[1])!==null&&o!==void 0?o:120,s=(a=(i=e[0])!==null&&i!==void 0?i:e[1])!==null&&a!==void 0?a:120));return[l,s]},gB=3,hB=e=>gB/e*100,mB=e=>{const{prefixCls:t,trailColor:n=null,strokeLinecap:r="round",gapPosition:o,gapDegree:i,width:a=120,type:l,children:s,success:c,size:u=a}=e,[d,v]=mf(u,"circle");let{strokeWidth:h}=e;h===void 0&&(h=Math.max(hB(d),6));const g={width:d,height:v,fontSize:d*.15+6},p=f.exports.useMemo(()=>{if(i||i===0)return i;if(l==="dashboard")return 75},[i,l]),b=o||l==="dashboard"&&"bottom"||void 0,m=Object.prototype.toString.call(e.strokeColor)==="[object Object]",y=pB({success:c,strokeColor:e.strokeColor}),S=te(`${t}-inner`,{[`${t}-circle-gradient`]:m}),x=C(fB,{percent:vB(e),strokeWidth:h,trailWidth:h,strokeColor:y,strokeLinecap:r,trailColor:n,prefixCls:t,gapDegree:p,gapPosition:b});return C("div",{className:S,style:g,children:d<=20?C(p2,{title:s,children:C("span",{children:x})}):ie(Tt,{children:[x,s]})})},yB=mB,ld="--progress-line-stroke-color",P$="--progress-percent",v1=e=>{const t=e?"100%":"-100%";return new Ct(`antProgress${e?"RTL":"LTR"}Active`,{"0%":{transform:`translateX(${t}) scaleX(0)`,opacity:.1},"20%":{transform:`translateX(${t}) scaleX(0)`,opacity:.5},to:{transform:"translateX(0) scaleX(1)",opacity:0}})},bB=e=>{const{componentCls:t,iconCls:n}=e;return{[t]:Object.assign(Object.assign({},Qt(e)),{display:"inline-block","&-rtl":{direction:"rtl"},"&-line":{position:"relative",width:"100%",fontSize:e.fontSize},[`${t}-outer`]:{display:"inline-block",width:"100%"},[`&${t}-show-info`]:{[`${t}-outer`]:{marginInlineEnd:`calc(-2em - ${X(e.marginXS)})`,paddingInlineEnd:`calc(2em + ${X(e.paddingXS)})`}},[`${t}-inner`]:{position:"relative",display:"inline-block",width:"100%",overflow:"hidden",verticalAlign:"middle",backgroundColor:e.remainingColor,borderRadius:e.lineBorderRadius},[`${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.defaultColor}},[`${t}-success-bg, ${t}-bg`]:{position:"relative",background:e.defaultColor,borderRadius:e.lineBorderRadius,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`},[`${t}-bg`]:{overflow:"hidden","&::after":{content:'""',background:{_multi_value_:!0,value:["inherit",`var(${ld})`]},height:"100%",width:`calc(1 / var(${P$}) * 100%)`,display:"block"}},[`${t}-success-bg`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,backgroundColor:e.colorSuccess},[`${t}-text`]:{display:"inline-block",width:"2em",marginInlineStart:e.marginXS,color:e.colorText,lineHeight:1,whiteSpace:"nowrap",textAlign:"start",verticalAlign:"middle",wordBreak:"normal",[n]:{fontSize:e.fontSize}},[`&${t}-status-active`]:{[`${t}-bg::before`]:{position:"absolute",inset:0,backgroundColor:e.colorBgContainer,borderRadius:e.lineBorderRadius,opacity:0,animationName:v1(),animationDuration:e.progressActiveMotionDuration,animationTimingFunction:e.motionEaseOutQuint,animationIterationCount:"infinite",content:'""'}},[`&${t}-rtl${t}-status-active`]:{[`${t}-bg::before`]:{animationName:v1(!0)}},[`&${t}-status-exception`]:{[`${t}-bg`]:{backgroundColor:e.colorError},[`${t}-text`]:{color:e.colorError}},[`&${t}-status-exception ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorError}},[`&${t}-status-success`]:{[`${t}-bg`]:{backgroundColor:e.colorSuccess},[`${t}-text`]:{color:e.colorSuccess}},[`&${t}-status-success ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorSuccess}}})}},SB=e=>{const{componentCls:t,iconCls:n}=e;return{[t]:{[`${t}-circle-trail`]:{stroke:e.remainingColor},[`&${t}-circle ${t}-inner`]:{position:"relative",lineHeight:1,backgroundColor:"transparent"},[`&${t}-circle ${t}-text`]:{position:"absolute",insetBlockStart:"50%",insetInlineStart:0,width:"100%",margin:0,padding:0,color:e.circleTextColor,fontSize:e.circleTextFontSize,lineHeight:1,whiteSpace:"normal",textAlign:"center",transform:"translateY(-50%)",[n]:{fontSize:e.circleIconFontSize}},[`${t}-circle&-status-exception`]:{[`${t}-text`]:{color:e.colorError}},[`${t}-circle&-status-success`]:{[`${t}-text`]:{color:e.colorSuccess}}},[`${t}-inline-circle`]:{lineHeight:1,[`${t}-inner`]:{verticalAlign:"bottom"}}}},CB=e=>{const{componentCls:t}=e;return{[t]:{[`${t}-steps`]:{display:"inline-block","&-outer":{display:"flex",flexDirection:"row",alignItems:"center"},"&-item":{flexShrink:0,minWidth:e.progressStepMinWidth,marginInlineEnd:e.progressStepMarginInlineEnd,backgroundColor:e.remainingColor,transition:`all ${e.motionDurationSlow}`,"&-active":{backgroundColor:e.defaultColor}}}}}},xB=e=>{const{componentCls:t,iconCls:n}=e;return{[t]:{[`${t}-small&-line, ${t}-small&-line ${t}-text ${n}`]:{fontSize:e.fontSizeSM}}}},wB=e=>({circleTextColor:e.colorText,defaultColor:e.colorInfo,remainingColor:e.colorFillSecondary,lineBorderRadius:100,circleTextFontSize:"1em",circleIconFontSize:`${e.fontSize/e.fontSizeSM}em`}),$B=vn("Progress",e=>{const t=e.calc(e.marginXXS).div(2).equal(),n=$t(e,{progressStepMarginInlineEnd:t,progressStepMinWidth:t,progressActiveMotionDuration:"2.4s"});return[bB(n),SB(n),CB(n),xB(n)]},wB);var EB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{let t=[];return Object.keys(e).forEach(n=>{const r=parseFloat(n.replace(/%/g,""));isNaN(r)||t.push({key:r,value:e[n]})}),t=t.sort((n,r)=>n.key-r.key),t.map(n=>{let{key:r,value:o}=n;return`${o} ${r}%`}).join(", ")},OB=(e,t)=>{const{from:n=Na.blue,to:r=Na.blue,direction:o=t==="rtl"?"to left":"to right"}=e,i=EB(e,["from","to","direction"]);if(Object.keys(i).length!==0){const l=MB(i),s=`linear-gradient(${o}, ${l})`;return{background:s,[ld]:s}}const a=`linear-gradient(${o}, ${n}, ${r})`;return{background:a,[ld]:a}},RB=e=>{const{prefixCls:t,direction:n,percent:r,size:o,strokeWidth:i,strokeColor:a,strokeLinecap:l="round",children:s,trailColor:c=null,success:u}=e,d=a&&typeof a!="string"?OB(a,n):{[ld]:a,background:a},v=l==="square"||l==="butt"?0:void 0,h=o!=null?o:[-1,i||(o==="small"?6:8)],[g,p]=mf(h,"line",{strokeWidth:i}),b={backgroundColor:c||void 0,borderRadius:v},m=Object.assign(Object.assign({width:`${Go(r)}%`,height:p,borderRadius:v},d),{[P$]:Go(r)/100}),y=ad(e),S={width:`${Go(y)}%`,height:p,borderRadius:v,backgroundColor:u==null?void 0:u.strokeColor},x={width:g<0?"100%":g,height:p};return ie(Tt,{children:[C("div",{className:`${t}-outer`,style:x,children:ie("div",{className:`${t}-inner`,style:b,children:[C("div",{className:`${t}-bg`,style:m}),y!==void 0?C("div",{className:`${t}-success-bg`,style:S}):null]})}),s]})},IB=RB,PB=e=>{const{size:t,steps:n,percent:r=0,strokeWidth:o=8,strokeColor:i,trailColor:a=null,prefixCls:l,children:s}=e,c=Math.round(n*(r/100)),u=t==="small"?2:14,d=t!=null?t:[u,o],[v,h]=mf(d,"step",{steps:n,strokeWidth:o}),g=v/n,p=new Array(n);for(let b=0;b{const{prefixCls:n,className:r,rootClassName:o,steps:i,strokeColor:a,percent:l=0,size:s="default",showInfo:c=!0,type:u="line",status:d,format:v,style:h}=e,g=NB(e,["prefixCls","className","rootClassName","steps","strokeColor","percent","size","showInfo","type","status","format","style"]),p=f.exports.useMemo(()=>{var F,T;const D=ad(e);return parseInt(D!==void 0?(F=D!=null?D:0)===null||F===void 0?void 0:F.toString():(T=l!=null?l:0)===null||T===void 0?void 0:T.toString(),10)},[l,e.success,e.successPercent]),b=f.exports.useMemo(()=>!_B.includes(d)&&p>=100?"success":d||"normal",[d,p]),{getPrefixCls:m,direction:y,progress:S}=f.exports.useContext(ot),x=m("progress",n),[$,E,w]=$B(x),R=f.exports.useMemo(()=>{if(!c)return null;const F=ad(e);let T;const D=v||(O=>`${O}%`),_=u==="line";return v||b!=="exception"&&b!=="success"?T=D(Go(l),Go(F)):b==="exception"?T=_?C(Nd,{}):C(eo,{}):b==="success"&&(T=_?C(NI,{}):C(lx,{})),C("span",{className:`${x}-text`,title:typeof T=="string"?T:void 0,children:T})},[c,l,p,b,u,x,v]),P=Array.isArray(a)?a[0]:a,N=typeof a=="string"||Array.isArray(a)?a:void 0;let I;u==="line"?I=i?C(TB,{...Object.assign({},e,{strokeColor:N,prefixCls:x,steps:i}),children:R}):C(IB,{...Object.assign({},e,{strokeColor:P,prefixCls:x,direction:y}),children:R}):(u==="circle"||u==="dashboard")&&(I=C(yB,{...Object.assign({},e,{strokeColor:P,prefixCls:x,progressStatus:b}),children:R}));const z=te(x,`${x}-status-${b}`,`${x}-${u==="dashboard"&&"circle"||i&&"steps"||u}`,{[`${x}-inline-circle`]:u==="circle"&&mf(s,"circle")[0]<=20,[`${x}-show-info`]:c,[`${x}-${s}`]:typeof s=="string",[`${x}-rtl`]:y==="rtl"},S==null?void 0:S.className,r,o,E,w);return $(C("div",{...Object.assign({ref:t,style:Object.assign(Object.assign({},S==null?void 0:S.style),h),className:z,role:"progressbar","aria-valuenow":p},lr(g,["trailColor","strokeWidth","width","gapDegree","gapPosition","strokeLinecap","success","successPercent"])),children:I}))}),DB=AB,LB=e=>{const{paddingXXS:t,lineWidth:n,tagPaddingHorizontal:r,componentCls:o,calc:i}=e,a=i(r).sub(n).equal(),l=i(t).sub(n).equal();return{[o]:Object.assign(Object.assign({},Qt(e)),{display:"inline-block",height:"auto",marginInlineEnd:e.marginXS,paddingInline:a,fontSize:e.tagFontSize,lineHeight:e.tagLineHeight,whiteSpace:"nowrap",background:e.defaultBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderRadius:e.borderRadiusSM,opacity:1,transition:`all ${e.motionDurationMid}`,textAlign:"start",position:"relative",[`&${o}-rtl`]:{direction:"rtl"},"&, a, a:hover":{color:e.defaultColor},[`${o}-close-icon`]:{marginInlineStart:l,fontSize:e.tagIconSize,color:e.colorTextDescription,cursor:"pointer",transition:`all ${e.motionDurationMid}`,"&:hover":{color:e.colorTextHeading}},[`&${o}-has-color`]:{borderColor:"transparent",[`&, a, a:hover, ${e.iconCls}-close, ${e.iconCls}-close:hover`]:{color:e.colorTextLightSolid}},["&-checkable"]:{backgroundColor:"transparent",borderColor:"transparent",cursor:"pointer",[`&:not(${o}-checkable-checked):hover`]:{color:e.colorPrimary,backgroundColor:e.colorFillSecondary},"&:active, &-checked":{color:e.colorTextLightSolid},"&-checked":{backgroundColor:e.colorPrimary,"&:hover":{backgroundColor:e.colorPrimaryHover}},"&:active":{backgroundColor:e.colorPrimaryActive}},["&-hidden"]:{display:"none"},[`> ${e.iconCls} + span, > span + ${e.iconCls}`]:{marginInlineStart:a}}),[`${o}-borderless`]:{borderColor:"transparent",background:e.tagBorderlessBg}}},Nm=e=>{const{lineWidth:t,fontSizeIcon:n,calc:r}=e,o=e.fontSizeSM;return $t(e,{tagFontSize:o,tagLineHeight:X(r(e.lineHeightSM).mul(o).equal()),tagIconSize:r(n).sub(r(t).mul(2)).equal(),tagPaddingHorizontal:8,tagBorderlessBg:e.defaultBg})},_m=e=>({defaultBg:new Mt(e.colorFillQuaternary).onBackground(e.colorBgContainer).toHexString(),defaultColor:e.colorText}),T$=vn("Tag",e=>{const t=Nm(e);return LB(t)},_m);var zB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:n,style:r,className:o,checked:i,onChange:a,onClick:l}=e,s=zB(e,["prefixCls","style","className","checked","onChange","onClick"]),{getPrefixCls:c,tag:u}=f.exports.useContext(ot),d=m=>{a==null||a(!i),l==null||l(m)},v=c("tag",n),[h,g,p]=T$(v),b=te(v,`${v}-checkable`,{[`${v}-checkable-checked`]:i},u==null?void 0:u.className,o,g,p);return h(C("span",{...Object.assign({},s,{ref:t,style:Object.assign(Object.assign({},r),u==null?void 0:u.style),className:b,onClick:d})}))}),kB=FB,BB=e=>ow(e,(t,n)=>{let{textColor:r,lightBorderColor:o,lightColor:i,darkColor:a}=n;return{[`${e.componentCls}${e.componentCls}-${t}`]:{color:r,background:i,borderColor:o,"&-inverse":{color:e.colorTextLightSolid,background:a,borderColor:a},[`&${e.componentCls}-borderless`]:{borderColor:"transparent"}}}}),jB=Kh(["Tag","preset"],e=>{const t=Nm(e);return BB(t)},_m);function HB(e){return typeof e!="string"?e:e.charAt(0).toUpperCase()+e.slice(1)}const Bc=(e,t,n)=>{const r=HB(n);return{[`${e.componentCls}${e.componentCls}-${t}`]:{color:e[`color${n}`],background:e[`color${r}Bg`],borderColor:e[`color${r}Border`],[`&${e.componentCls}-borderless`]:{borderColor:"transparent"}}}},WB=Kh(["Tag","status"],e=>{const t=Nm(e);return[Bc(t,"success","Success"),Bc(t,"processing","Info"),Bc(t,"error","Error"),Bc(t,"warning","Warning")]},_m);var VB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:n,className:r,rootClassName:o,style:i,children:a,icon:l,color:s,onClose:c,closeIcon:u,closable:d,bordered:v=!0}=e,h=VB(e,["prefixCls","className","rootClassName","style","children","icon","color","onClose","closeIcon","closable","bordered"]),{getPrefixCls:g,direction:p,tag:b}=f.exports.useContext(ot),[m,y]=f.exports.useState(!0);f.exports.useEffect(()=>{"visible"in h&&y(h.visible)},[h.visible]);const S=d2(s),x=ID(s),$=S||x,E=Object.assign(Object.assign({backgroundColor:s&&!$?s:void 0},b==null?void 0:b.style),i),w=g("tag",n),[R,P,N]=T$(w),I=te(w,b==null?void 0:b.className,{[`${w}-${s}`]:$,[`${w}-has-color`]:s&&!$,[`${w}-hidden`]:!m,[`${w}-rtl`]:p==="rtl",[`${w}-borderless`]:!v},r,o,P,N),z=M=>{M.stopPropagation(),c==null||c(M),!M.defaultPrevented&&y(!1)},[,F]=m6(d,u!=null?u:b==null?void 0:b.closeIcon,M=>M===null?C(eo,{className:`${w}-close-icon`,onClick:z}):C("span",{className:`${w}-close-icon`,onClick:z,children:M}),null,!1),T=typeof h.onClick=="function"||a&&a.type==="a",D=l||null,_=D?ie(Tt,{children:[D,a&&C("span",{children:a})]}):a,O=ie("span",{...Object.assign({},h,{ref:t,className:I,style:E}),children:[_,F,S&&C(jB,{prefixCls:w},"preset"),x&&C(WB,{prefixCls:w},"status")]});return R(T?C(Qh,{component:"Tag",children:O}):O)},N$=f.exports.forwardRef(UB);N$.CheckableTag=kB;const oa=N$;function YB(e){return window.go.main.App.ExportWeChatAllData(e)}function GB(){return window.go.main.App.GetAppVersion()}function KB(){return window.go.main.App.GetWeChatAllInfo()}function qB(e){return window.go.main.App.GetWeChatRoomUserList(e)}function XB(e){return window.go.main.App.GetWechatMessageDate(e)}function QB(e,t,n,r,o){return window.go.main.App.GetWechatMessageListByKeyWord(e,t,n,r,o)}function p1(e,t,n,r){return window.go.main.App.GetWechatMessageListByTime(e,t,n,r)}function ZB(e,t){return window.go.main.App.GetWechatSessionList(e,t)}function JB(e,t){return window.go.main.App.OpenFileOrExplorer(e,t)}function e9(){return window.go.main.App.WeChatInit()}const t9="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";let Am=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e));for(;e--;)t+=t9[n[e]&63];return t};function Ts(e){window.runtime.LogInfo(e)}function n9(e,t,n){return window.runtime.EventsOnMultiple(e,t,n)}function _$(e,t){return n9(e,t,-1)}function A$(e,...t){return window.runtime.EventsOff(e,...t)}function r9(){window.runtime.WindowToggleMaximise()}function o9(){window.runtime.WindowMinimise()}function i9(e){window.runtime.BrowserOpenURL(e)}function a9(){window.runtime.Quit()}function l9(e,t){let n;return function(...r){n&&clearTimeout(n),n=setTimeout(()=>{e.apply(this,r)},t)}}function s9(e){return C("div",{className:"wechat-SearchBar",children:C(ai,{theme:{components:{Input:{activeBorderColor:"#E3E4E5",activeShadow:"#E3E4E5",hoverBorderColor:"#E3E4E5"}}},children:C(C$,{className:"wechat-SearchBar-Input",placeholder:"\u641C\u7D22",prefix:C(_d,{}),allowClear:!0,onChange:t=>e.onChange(t.target.value)})})})}function c9(e){return ie("div",{className:`${e.className} wechat-UserItem`,onClick:e.onClick,tabIndex:"0",children:[C(Yo,{id:"wechat-UserItem-content-Avatar-id",className:"wechat-UserItem-content-Avatar",src:e.Avatar,size:{xs:45,sm:45,md:45,lg:45,xl:45,xxl:45},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"}),ie("div",{className:"wechat-UserItem-content",children:[C("div",{className:"wechat-UserItem-content-text wechat-UserItem-content-name",children:e.name}),C("div",{className:"wechat-UserItem-content-text wechat-UserItem-content-msg",children:e.msg})]}),C("div",{className:"wechat-UserItem-date",children:e.date})]})}function u9(e){const t=new Date(e*1e3),n=t.getFullYear(),r=t.getMonth()+1,o=t.getDate();return t.getHours(),t.getMinutes(),t.getSeconds(),`${n-2e3}/${r}/${o}`}function d9(e){const[t,n]=f.exports.useState(null),[r,o]=f.exports.useState(0),[i,a]=f.exports.useState(!0),[l,s]=f.exports.useState([]),[c,u]=f.exports.useState(""),d=(g,p)=>{n(g),e.onClickItem&&e.onClickItem(p)};f.exports.useEffect(()=>{i&&e.selfName!==""&&ZB(r,20).then(g=>{var p=JSON.parse(g);if(p.Total>0){let b=[];p.Rows.forEach(m=>{m.UserName.startsWith("gh_")||b.push(m)}),s(m=>[...m,...b]),o(m=>m+1)}else a(!1)})},[r,i,e.selfName]);const v=f.exports.useCallback(l9(g=>{console.log(g),u(g)},400),[]),h=l.filter(g=>g.NickName.includes(c));return ie("div",{className:"wechat-UserList",onClick:e.onClick,children:[C(s9,{onChange:v}),C("div",{className:"wechat-UserList-Items",children:h.map((g,p)=>C(c9,{className:t===p?"selectedItem":"",onClick:()=>{d(p,g)},name:g.NickName,msg:g.Content,date:u9(g.Time),Avatar:g.UserInfo.SmallHeadImgUrl},Am()))})]})}const ia={INIT:"normal",START:"active",END:"success",ERROR:"exception"};function f9({info:e,appVersion:t}){const[n,r]=f.exports.useState({});return f.exports.useEffect(()=>{r({PID:e.PID,path:e.FilePath,version:e.Version!==""?e.Version+" "+(e.Is64Bits?"64bits":"32bits"):"\u7248\u672C\u83B7\u53D6\u5931\u8D25",userName:e.AcountName,result:e.DBkey&&e.DBkey.length>0?"success":"failed"})},[e]),ie(Tt,{children:[C("div",{children:"\u5F53\u524D\u767B\u9646\u7684\u5FAE\u4FE1\u4FE1\u606F"}),ie("div",{className:"WechatInfoTable",children:[ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"wechatDataBackup \u7248\u672C:"}),C(oa,{className:"WechatInfoTable-column-tag",color:"success",children:t})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u8FDB\u7A0BPID:"}),C(oa,{className:"WechatInfoTable-column-tag",color:n.PID===0?"red":"success",children:n.PID===0?"\u5F53\u524D\u6CA1\u6709\u6253\u5F00\u5FAE\u4FE1":n.PID})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u6587\u4EF6\u5B58\u50A8\u8DEF\u5F84:"}),C(oa,{className:"WechatInfoTable-column-tag",color:"success",children:n.path})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u5FAE\u4FE1\u8F6F\u4EF6\u7248\u672C:"}),C(oa,{className:"WechatInfoTable-column-tag",color:"success",children:n.version})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u5FAE\u4FE1ID:"}),C(oa,{className:"WechatInfoTable-column-tag",color:n.userName===""?"red":"success",children:n.userName===""?"\u5F53\u524D\u6CA1\u6709\u767B\u9646\u5FAE\u4FE1":n.userName})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u89E3\u5BC6\u7ED3\u679C:"}),C(oa,{className:"WechatInfoTable-column-tag",color:n.result==="success"?"green":"red",children:n.result==="success"?"\u89E3\u5BC6\u6210\u529F":"\u89E3\u5BC6\u5931\u8D25"})]})]})]})}function v9(e){const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState({}),[i,a]=f.exports.useState(-1),[l,s]=f.exports.useState(ia.INIT),[c,u]=f.exports.useState(""),d=p=>{console.log(p);const b=JSON.parse(p);b.status==="error"?(s(ia.ERROR),a(100)):(s(b.progress!==100?ia.START:ia.END),a(b.progress))},v=()=>{console.log("showModal"),n(!0),KB().then(p=>{console.log(p),o(JSON.parse(p))}),GB().then(p=>{u(p)}),_$("exportData",d)},h=p=>{n(!1),a(-1),s(ia.INIT),A$("exportData"),e.onModalExit&&e.onModalExit()},g=p=>{YB(p),a(0),s(ia.START)};return ie("div",{className:"Setting-Modal-Parent",children:[C("div",{onClick:v,children:e.children}),ie(js,{className:"Setting-Modal",overlayClassName:"Setting-Modal-Overlay",isOpen:t,onRequestClose:h,children:[C("div",{className:"Setting-Modal-button",title:"\u5173\u95ED",onClick:()=>h(),children:C(eo,{className:"Setting-Modal-button-icon"})}),C(f9,{info:r,appVersion:c}),r.DBkey&&r.DBkey.length>0&&C(p9,{onClickExport:g,children:C(Xu,{className:"Setting-Modal-export-button",type:"primary",children:"\u5BFC\u51FA\u6B64\u8D26\u53F7\u6570\u636E"})}),i>-1&&C(DB,{percent:i,status:l})]})]})}const p9=e=>{const[t,n]=f.exports.useState(!1),r=i=>{n(!1)},o=i=>{n(!1),e.onClickExport&&e.onClickExport(i)};return ie("div",{className:"Setting-Modal-confirm-Parent",children:[C("div",{onClick:()=>n(!0),children:e.children}),ie(js,{className:"Setting-Modal-confirm",overlayClassName:"Setting-Modal-confirm-Overlay",isOpen:t,onRequestClose:r,children:[C("div",{className:"Setting-Modal-confirm-title",children:"\u9009\u62E9\u5BFC\u51FA\u65B9\u5F0F"}),ie("div",{className:"Setting-Modal-confirm-buttons",children:[C(Xu,{className:"Setting-Modal-export-button",type:"primary",onClick:()=>o(!0),children:"\u5168\u91CF\u5BFC\u51FA\uFF08\u901F\u5EA6\u6162\uFF09"}),C(Xu,{className:"Setting-Modal-export-button",type:"primary",onClick:()=>o(!1),children:"\u589E\u91CF\u5BFC\u51FA\uFF08\u901F\u5EA6\u5FEB\uFF09"})]})]})]})};function g9(e){const[t,n]=f.exports.useState("chat"),r=o=>{o!=="avatar"&&n(o),e.onClickItem&&e.onClickItem(o)};return ie("div",{className:"wechat-menu",children:[C(Yo,{id:"wechat-menu-item-Avatar",className:"wechat-menu-item wechat-menu-item-Avatar",src:e.Avatar,size:"large",shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF",onClick:()=>r("avatar")}),C(Yo,{icon:C($4,{}),title:"\u67E5\u770B\u804A\u5929",className:`wechat-menu-item wechat-menu-item-icon ${t==="chat"?"wechat-menu-selectedColor":""}`,size:"default",onClick:()=>r("chat")}),C(v9,{onModalExit:()=>e.onClickItem("exit"),children:C(Yo,{icon:C(c4,{}),title:"\u8BBE\u7F6E",className:`wechat-menu-item wechat-menu-item-icon ${t==="setting"?"wechat-menu-selectedColor":""}`,size:"default"})})]})}var Ng=function(e,t){return Ng=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,r){n.__proto__=r}||function(n,r){for(var o in r)r.hasOwnProperty(o)&&(n[o]=r[o])},Ng(e,t)};function h9(e,t){Ng(e,t);function n(){this.constructor=e}e.prototype=t===null?Object.create(t):(n.prototype=t.prototype,new n)}var es=function(){return es=Object.assign||function(t){for(var n,r=1,o=arguments.length;re?h():t!==!0&&(o=setTimeout(r?g:h,r===void 0?e-d:e))}return c.cancel=s,c}var La={Pixel:"Pixel",Percent:"Percent"},g1={unit:La.Percent,value:.8};function h1(e){return typeof e=="number"?{unit:La.Percent,value:e*100}:typeof e=="string"?e.match(/^(\d*(\.\d+)?)px$/)?{unit:La.Pixel,value:parseFloat(e)}:e.match(/^(\d*(\.\d+)?)%$/)?{unit:La.Percent,value:parseFloat(e)}:(console.warn('scrollThreshold format is invalid. Valid formats: "120px", "50%"...'),g1):(console.warn("scrollThreshold should be string or number"),g1)}var D$=function(e){h9(t,e);function t(n){var r=e.call(this,n)||this;return r.lastScrollTop=0,r.actionTriggered=!1,r.startY=0,r.currentY=0,r.dragging=!1,r.maxPullDownDistance=0,r.getScrollableTarget=function(){return r.props.scrollableTarget instanceof HTMLElement?r.props.scrollableTarget:typeof r.props.scrollableTarget=="string"?document.getElementById(r.props.scrollableTarget):(r.props.scrollableTarget===null&&console.warn(`You are trying to pass scrollableTarget but it is null. This might + happen because the element may not have been added to DOM yet. + See https://github.com/ankeetmaini/react-infinite-scroll-component/issues/59 for more info. + `),null)},r.onStart=function(o){r.lastScrollTop||(r.dragging=!0,o instanceof MouseEvent?r.startY=o.pageY:o instanceof TouchEvent&&(r.startY=o.touches[0].pageY),r.currentY=r.startY,r._infScroll&&(r._infScroll.style.willChange="transform",r._infScroll.style.transition="transform 0.2s cubic-bezier(0,0,0.31,1)"))},r.onMove=function(o){!r.dragging||(o instanceof MouseEvent?r.currentY=o.pageY:o instanceof TouchEvent&&(r.currentY=o.touches[0].pageY),!(r.currentY=Number(r.props.pullDownToRefreshThreshold)&&r.setState({pullToRefreshThresholdBreached:!0}),!(r.currentY-r.startY>r.maxPullDownDistance*1.5)&&r._infScroll&&(r._infScroll.style.overflow="visible",r._infScroll.style.transform="translate3d(0px, "+(r.currentY-r.startY)+"px, 0px)")))},r.onEnd=function(){r.startY=0,r.currentY=0,r.dragging=!1,r.state.pullToRefreshThresholdBreached&&(r.props.refreshFunction&&r.props.refreshFunction(),r.setState({pullToRefreshThresholdBreached:!1})),requestAnimationFrame(function(){r._infScroll&&(r._infScroll.style.overflow="auto",r._infScroll.style.transform="none",r._infScroll.style.willChange="unset")})},r.onScrollListener=function(o){typeof r.props.onScroll=="function"&&setTimeout(function(){return r.props.onScroll&&r.props.onScroll(o)},0);var i=r.props.height||r._scrollableNode?o.target:document.documentElement.scrollTop?document.documentElement:document.body;if(!r.actionTriggered){var a=r.props.inverse?r.isElementAtTop(i,r.props.scrollThreshold):r.isElementAtBottom(i,r.props.scrollThreshold);a&&r.props.hasMore&&(r.actionTriggered=!0,r.setState({showLoader:!0}),r.props.next&&r.props.next()),r.lastScrollTop=i.scrollTop}},r.state={showLoader:!1,pullToRefreshThresholdBreached:!1,prevDataLength:n.dataLength},r.throttledOnScrollListener=m9(150,r.onScrollListener).bind(r),r.onStart=r.onStart.bind(r),r.onMove=r.onMove.bind(r),r.onEnd=r.onEnd.bind(r),r}return t.prototype.componentDidMount=function(){if(typeof this.props.dataLength>"u")throw new Error('mandatory prop "dataLength" is missing. The prop is needed when loading more content. Check README.md for usage');if(this._scrollableNode=this.getScrollableTarget(),this.el=this.props.height?this._infScroll:this._scrollableNode||window,this.el&&this.el.addEventListener("scroll",this.throttledOnScrollListener),typeof this.props.initialScrollY=="number"&&this.el&&this.el instanceof HTMLElement&&this.el.scrollHeight>this.props.initialScrollY&&this.el.scrollTo(0,this.props.initialScrollY),this.props.pullDownToRefresh&&this.el&&(this.el.addEventListener("touchstart",this.onStart),this.el.addEventListener("touchmove",this.onMove),this.el.addEventListener("touchend",this.onEnd),this.el.addEventListener("mousedown",this.onStart),this.el.addEventListener("mousemove",this.onMove),this.el.addEventListener("mouseup",this.onEnd),this.maxPullDownDistance=this._pullDown&&this._pullDown.firstChild&&this._pullDown.firstChild.getBoundingClientRect().height||0,this.forceUpdate(),typeof this.props.refreshFunction!="function"))throw new Error(`Mandatory prop "refreshFunction" missing. + Pull Down To Refresh functionality will not work + as expected. Check README.md for usage'`)},t.prototype.componentWillUnmount=function(){this.el&&(this.el.removeEventListener("scroll",this.throttledOnScrollListener),this.props.pullDownToRefresh&&(this.el.removeEventListener("touchstart",this.onStart),this.el.removeEventListener("touchmove",this.onMove),this.el.removeEventListener("touchend",this.onEnd),this.el.removeEventListener("mousedown",this.onStart),this.el.removeEventListener("mousemove",this.onMove),this.el.removeEventListener("mouseup",this.onEnd)))},t.prototype.componentDidUpdate=function(n){this.props.dataLength!==n.dataLength&&(this.actionTriggered=!1,this.setState({showLoader:!1}))},t.getDerivedStateFromProps=function(n,r){var o=n.dataLength!==r.prevDataLength;return o?es(es({},r),{prevDataLength:n.dataLength}):null},t.prototype.isElementAtTop=function(n,r){r===void 0&&(r=.8);var o=n===document.body||n===document.documentElement?window.screen.availHeight:n.clientHeight,i=h1(r);return i.unit===La.Pixel?n.scrollTop<=i.value+o-n.scrollHeight+1:n.scrollTop<=i.value/100+o-n.scrollHeight+1},t.prototype.isElementAtBottom=function(n,r){r===void 0&&(r=.8);var o=n===document.body||n===document.documentElement?window.screen.availHeight:n.clientHeight,i=h1(r);return i.unit===La.Pixel?n.scrollTop+o>=n.scrollHeight-i.value:n.scrollTop+o>=i.value/100*n.scrollHeight},t.prototype.render=function(){var n=this,r=es({height:this.props.height||"auto",overflow:"auto",WebkitOverflowScrolling:"touch"},this.props.style),o=this.props.hasChildren||!!(this.props.children&&this.props.children instanceof Array&&this.props.children.length),i=this.props.pullDownToRefresh&&this.props.height?{overflow:"auto"}:{};return C("div",{style:i,className:"infinite-scroll-component__outerdiv",children:ie("div",{className:"infinite-scroll-component "+(this.props.className||""),ref:function(a){return n._infScroll=a},style:r,children:[this.props.pullDownToRefresh&&C("div",{style:{position:"relative"},ref:function(a){return n._pullDown=a},children:C("div",{style:{position:"absolute",left:0,right:0,top:-1*this.maxPullDownDistance},children:this.state.pullToRefreshThresholdBreached?this.props.releaseToRefreshContent:this.props.pullDownToRefreshContent})}),this.props.children,!this.state.showLoader&&!o&&this.props.hasMore&&this.props.loader,this.state.showLoader&&this.props.hasMore&&this.props.loader,!this.props.hasMore&&this.props.endMessage]})})},t}(f.exports.Component);const y9=f.exports.forwardRef((e,t)=>{let n=!1,r=!1;e.message.position==="middle"?n=!0:r=e.message.position!=="right";const o=f.exports.useMemo(()=>e.renderMessageContent(e.message),[e.message]);return ie("div",{className:"MessageBubble",id:e.id,ref:t,children:[C("time",{className:"Time",dateTime:Lt(e.message.createdAt).format(),children:Lt(e.message.createdAt*1e3).format("YYYY\u5E74M\u6708D\u65E5 HH:mm")}),n?o:ie("div",{className:"MessageBubble-content"+(r?"-left":"-right"),children:[C("div",{className:"MessageBubble-content-Avatar",children:r&&C(Yo,{className:"MessageBubble-Avatar-left",src:e.message.user.avatar,size:{xs:40,sm:40,md:40,lg:40,xl:40,xxl:40},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"})}),ie("div",{className:"Bubble"+(r?"-left":"-right"),children:[C("div",{className:"MessageBubble-Name"+(r?"-left":"-right"),truncate:1,children:e.message.user.name}),o]}),C("div",{className:"MessageBubble-content-Avatar",children:!r&&C(Yo,{className:"MessageBubble-Avatar-right",src:e.message.user.avatar,size:{xs:40,sm:40,md:40,lg:40,xl:40,xxl:40},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"})})]})]})});function b9(e){const t=f.exports.useRef(),n=f.exports.useRef(0),r=f.exports.useRef(null),o=a=>{a.srcElement.scrollTop>0&&a.srcElement.scrollTop<1&&(a.srcElement.scrollTop=0),a.srcElement.scrollTop===0?(n.current=a.srcElement.scrollHeight,r.current=a.srcElement,e.atBottom&&e.atBottom()):(n.current=0,r.current=null)};function i(){e.next()}return f.exports.useEffect(()=>{n.current!==0&&r.current&&(r.current.scrollTop=-(r.current.scrollHeight-n.current),n.current=0,r.current=null)},[e.messages]),f.exports.useEffect(()=>{t.current&&t.current.scrollIntoView()},[e.messages]),C("div",{id:"scrollableDiv",children:C(D$,{scrollableTarget:"scrollableDiv",dataLength:e.messages.length,next:i,hasMore:e.hasMore,inverse:!0,onScroll:o,children:e.messages.map(a=>C(y9,{message:a,renderMessageContent:e.renderMessageContent,id:a.key,ref:a.key===e.scrollIntoId?t:null},a.key))})})}function S9(e){return C("div",{className:"ChatUi",children:C(b9,{messages:e.messages,next:e.fetchMoreData,hasMore:e.hasMore,renderMessageContent:e.renderMessageContent,atBottom:e.atBottom,scrollIntoId:e.scrollIntoId})})}function L$(e){const[t,n]=f.exports.useState(e);return{messages:t,prependMsgs:a=>{n(a.concat(t))},appendMsgs:a=>{n(t.concat(a))},setMsgs:a=>{n(a)}}}const C9="data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCABXAFcDASIAAhEBAxEB/8QAHQABAAICAgMAAAAAAAAAAAAAAAkKBQcCAwQGCP/EACkQAAEEAgIBBAIBBQAAAAAAAAQCAwUGAAEHCAkREhMUFSEiIyUxUWH/xAAZAQEBAQEBAQAAAAAAAAAAAAAAAQIDBAX/xAAjEQACAgAGAgMBAAAAAAAAAAAAAQIREiExQVFhInGBwfAD/9oADAMBAAIRAxEAPwC/BjGM+gecYxjAGMYwBjGMAYxjAGMYwBjGMAYxjAGMw1isUDUYCatVomI6v1uuRZ83PTswWxHxUPERgzhkjJSJxK2xxAghWXSCCHnENtNNqWtWta3la/lXvv3N8inMc5wP41RZGg8WU434LRzpI7TXy5UdfzDMzcpYHBZZykVaRJEkXaxExIZN7sIDDUiUJHkbNrkZmUlGrtt6JZt/uypX9t6Is04yrfe+sXmz6lxLfMVO7Ouc9D15KJe1UqItljur/wBILSjZPRFQ5GrceDPQeh2FtEuQZbFj+JxxQAAriUEomA8cffqq97uIirBsIGr8s0V4KJ5Towr7jjEeaaghUXYoNJK1mLrNiSGYoH7CnXwDgpGKIfIWGgsqRnbwtOL1Se/rkNUrTTXW3vgkQxjGbIMYxgDGMYAzGzEzEV6KkJ2flY2DhIkR+QlZiYOFjIqMAFbU8SbISBrrAgQg7SVOvkkvNsstpUtxaU63vXkmmhxoZcjIljAR4Az5pxxj7QwgYYrS3ySiiXlIZHGHZQt5991aG2mkKcWpKU73qrX2F57578xfOxvVTqkuTqHUukzQTnJXKJQzzUfaRxSG2XbPYXRk6VuI+wiS3xzx81Jtk23QzFlsCQHG9C0/MpKKWVt6R3bKlfSWr4/bImX8ifT2693+FYPjOi8zlcYCt2mKm50XQ+j6peYHbwunR53QDf5UlcMN80xXBhjW4c+V003LsKTsGUh/WQLX0i8SPEHFnEc3ZwaMFbJgaNYLeYcl7jdZ55Qo9i5FtbQenDkQwT5DC5aV20mHr4jwUTGsNsNiB5juwPZvhnxTdUaLTJGxzPItxrtQ1UuJafY7DuQu/IEnFD+38rOGPLfJiqjFlksalJJodwKDjlgwMII89qMj1RmdFeivLPejljffzv796Yhpg0Sb4p4smhHwQZyNGedIgCSYJf10Q3GUI3oRdYgttPKuelLmJtwsEl8ix4k6l4xT/o0rttqK74+KvXdJ1LLN1FXXLfXPv8rMgRwEtHiSUeULIRcmGOcEaM62SGcAawh8Yod5va2nxSR3EOtOoUpt1paVp3tKtb3WX8TrMGx5Su/zPFem08Tsmcltgojdt/gkDp5hQmBRG/W39TcW2rUsivfHtX9n0nbW9o+RWbi8kHkP5Bnr+vx79F4WWsPNFkKdoV9tFdA176kl5lseQqNU9WVMBFAxezFXC3v6DjaRFMPuCltmDlyEJIJ44Ohtb6LcLIrpJMfY+YLz+PnuXLoG09ocyabG3serQTxW9FuVaqLJMEjCn2QSJsp46wFxsW9Jpio83jmq0g23La+F9kqk73WS6tO/WWXJIdjGM6kGMYwBjGMAjq8sk9O13x8dkza88QOYVUY6GLfF2pLzcNO2aEiJtOlp/khsiLMKFf3r0/oPu69devrrWPhRpFEq3j54jnaixHuTF9OvFivkuO0hB8jZxLzY6+kWSX+3vdBRERGw4jS9pb+sKk1lvWj1uuyRcscY1LmjjS9cT3sJchUOQqxL1SwCtPLHI3Hy4jgrj4ZLe9OCnCKWgsApvfvGMYYfR/JvWVb6Va+8PhLu1o47M4mL7EdWrXYTLFAzcW1NCRzzim2Q0GB2mLirA1QLM6I2Emdrk9CGBSJAyyYhRDOlSe+cnhmpu8OFxbq8Lu7fvQ0s41vdrvYnJ518a/XnsT2a4/7N8nMTk7L0iIGjTaIacoujWx2FI+1VypiNJUvbDEM+4U4bEhbai7FtbCZkZ9tspB2AH8nHXx/uRAdKqXHT1ym32SYKQu1HC1O06r3EBLfsp5I8OwS9sKLDaLRZLGwpELUTBUgSe0tsypUREryT5Tu6vecPfAHTLrBceMJO7tuQdg5CJlzJqXi4eRHWNIrYsTlbrFa47HaZcI+eymSRsk20lK4dcdJaa2qWHxyeOOidG6GuSlXo+89gLqCM9yPyQsRSkhLcUstynU1Zq3zA63HEv7aOk97EkLocK1OS4gDSIqCg4pYpeCyu5SaeeipXvXrnfM1S8nmskr0960utz7fjeE+JYflOwc3RfH9ZC5ZtMFHVqfvrEc2mwSULFLeWGE6Vve0t/p7TZZI7bRciwNHDSD5Q8XGtC7RxjOtJaKt/nkyMYxgDGMYAxjGAM4ONodQpt1CHG169FIcTpaFa/wBKSrW071/zet6znjAOgcUYRG2xR2Bm97920Dstso2r/Hu2ltKU736fr13r1zvxjAGMYwBjGMAYxjAGMYwBjGMAYxjAGMYwBjGMAYxjAP/Z",x9="/assets/emoji.b5d5ea11.png",w9="/assets/001_\u5FAE\u7B11.1ec7a344.png",$9="/assets/002_\u6487\u5634.0279218b.png",E9="/assets/003_\u8272.e92bb91a.png",M9="/assets/004_\u53D1\u5446.8d849292.png",O9="/assets/005_\u5F97\u610F.72060784.png",R9="/assets/006_\u6D41\u6CEA.f52e5f23.png",I9="/assets/007_\u5BB3\u7F9E.414541cc.png",P9="/assets/008_\u95ED\u5634.4b6c78a6.png",T9="/assets/009_\u7761.75e64219.png",N9="/assets/010_\u5927\u54ED.2cd2fee3.png",_9="/assets/011_\u5C34\u5C2C.70cfea1c.png",A9="/assets/012_\u53D1\u6012.b88ce021.png",D9="/assets/013_\u8C03\u76AE.f3363541.png",L9="/assets/014_\u5472\u7259.3cd1fb7c.png",z9="/assets/015_\u60CA\u8BB6.c9eb5e15.png",F9="/assets/016_\u96BE\u8FC7.5d872489.png",k9="/assets/017_\u56E7.59ee6551.png",B9="/assets/018_\u6293\u72C2.d1646df8.png",j9="/assets/019_\u5410.51bb226f.png",H9="/assets/020_\u5077\u7B11.59941b0b.png",W9="/assets/021_\u6109\u5FEB.47582f99.png",V9="/assets/022_\u767D\u773C.ca492234.png",U9="/assets/023_\u50B2\u6162.651b4c79.png",Y9="/assets/024_\u56F0.4556c7db.png",G9="/assets/025_\u60CA\u6050.ed5cfeab.png",K9="/assets/026_\u61A8\u7B11.6d317a05.png",q9="/assets/027_\u60A0\u95F2.cef28253.png",X9="/assets/028_\u5492\u9A82.a26d48fa.png",Q9="/assets/029_\u7591\u95EE.aaa09269.png",Z9="/assets/030_\u5618.40e8213d.png",J9="/assets/031_\u6655.44e3541a.png",ej="/assets/032_\u8870.1a3910a6.png",tj="/assets/033_\u9AB7\u9AC5.3c9202dc.png",nj="/assets/034_\u6572\u6253.b2798ca7.png",rj="/assets/035_\u518D\u89C1.db23652c.png",oj="/assets/036_\u64E6\u6C57.b46fa893.png",ij="/assets/037_\u62A0\u9F3B.64bc8033.png",aj="/assets/038_\u9F13\u638C.2a84e4c7.png",lj="/assets/039_\u574F\u7B11.4998b91f.png",sj="/assets/040_\u53F3\u54FC\u54FC.27d8126d.png",cj="/assets/041_\u9119\u89C6.7e22890d.png",uj="/assets/042_\u59D4\u5C48.a5caf83a.png",dj="/assets/043_\u5FEB\u54ED\u4E86.62b1b67c.png",fj="/assets/044_\u9634\u9669.3697222b.png",vj="/assets/045_\u4EB2\u4EB2.dfa6bbdf.png",pj="/assets/046_\u53EF\u601C.634845ad.png",gj="/assets/047_\u7B11\u8138.ab25a28c.png",hj="/assets/048_\u751F\u75C5.cd7aadb3.png",mj="/assets/049_\u8138\u7EA2.9ecb5c1c.png",yj="/assets/050_\u7834\u6D95\u4E3A\u7B11.a3d2342d.png",bj="/assets/051_\u6050\u60E7.7af18313.png",Sj="/assets/052_\u5931\u671B.87e0479b.png",Cj="/assets/053_\u65E0\u8BED.6220ee7c.png",xj="/assets/054_\u563F\u54C8.2116e692.png",wj="/assets/055_\u6342\u8138.28f3a0d3.png",$j="/assets/056_\u5978\u7B11.9cf99423.png",Ej="/assets/057_\u673A\u667A.93c3d05a.png",Mj="/assets/058_\u76B1\u7709.efe09ed7.png",Oj="/assets/059_\u8036.a6bc3d2b.png",Rj="/assets/060_\u5403\u74DC.a2a158de.png",Ij="/assets/061_\u52A0\u6CB9.77c81f5b.png",Pj="/assets/062_\u6C57.be95535c.png",Tj="/assets/063_\u5929\u554A.a8355bf9.png",Nj="/assets/064_Emm.787be530.png",_j="/assets/065_\u793E\u4F1A\u793E\u4F1A.a5f5902a.png",Aj="/assets/066_\u65FA\u67F4.7825a175.png",Dj="/assets/067_\u597D\u7684.a9fffc64.png",Lj="/assets/068_\u6253\u8138.560c8d1f.png",zj="/assets/069_\u54C7.74cdcc27.png",Fj="/assets/070_\u7FFB\u767D\u773C.ecb744e2.png",kj="/assets/071_666.281fb9b6.png",Bj="/assets/072_\u8BA9\u6211\u770B\u770B.cee96a9f.png",jj="/assets/073_\u53F9\u6C14.712846f3.png",Hj="/assets/074_\u82E6\u6DA9.4edf4f58.png",Wj="/assets/075_\u88C2\u5F00.3fb97804.png",Vj="/assets/076_\u5634\u5507.59b9c0be.png",Uj="/assets/077_\u7231\u5FC3.a09c823b.png",Yj="/assets/078_\u5FC3\u788E.9a4fb37d.png",Gj="/assets/079_\u62E5\u62B1.e529a46b.png",Kj="/assets/080_\u5F3A.64fe98a8.png",qj="/assets/081_\u5F31.07ddf3a5.png",Xj="/assets/082_\u63E1\u624B.aeb86265.png",Qj="/assets/083_\u80DC\u5229.e9ff0663.png",Zj="/assets/084_\u62B1\u62F3.0ae5f316.png",Jj="/assets/085_\u52FE\u5F15.a4c3a7b4.png",eH="/assets/086_\u62F3\u5934.2829fdbe.png",tH="/assets/087_OK.fc42db3d.png",nH="/assets/088_\u5408\u5341.58cd6a1d.png",rH="/assets/089_\u5564\u9152.2d022508.png",oH="/assets/090_\u5496\u5561.8f40dc95.png",iH="/assets/091_\u86CB\u7CD5.f01a91ed.png",aH="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAADAFBMVEUAAABBhg5CiQ4/hQtLjBCQUgtDhg6VIA+6HQk/hw1FiA6TIRBDhg0/hw2hIA5Ahw1DiBBDhw6fHw67HQuQIBCLHw9CiA64HwuqJQ2PIRGUIBCVIBCUIBCmHw2aHw9Dhg6QIRGSIRCTIRCUHxCUIBCrHgxOkRpFhw02fwQ/hQ2YIA9HixCvHgu91aton0BHixFcnSWJtGnAIgubHw5YbwxUaQllrhmAt0GKIBBTkxykxosxfQBIeQ5TcQ/EFQQ4WQraHgWSIBFAhg5kiQ3eHwXPGgU+eQyM0jBUeQzgIAbVHARNihme1UKPIBGFGQ3YHQVmpQzJGAWHvDltljNwyBJAgg1BiQ7uWEyOHg/GFQToPyx+FQzTGwXiJQvnOyfmNR+CFwzNGQXvW1A/fQ17FAv0cGvsUkSPIhOKHQ/tVUjkLxfIFgTpRjWMHQ7wYFbsTkDpQjHkMhvrTDzjKRA7awuAFgzhIgfcHgXwXlTjLBPxZV3qSTlljA06ZguUIRGIGw46XwrmOCPLFwTya2XyaWI9dgw9cAzzbmiUJRd2yhdssRDRGgSnOjGaLCB8yh+YKBtvwRE9hgw9XwpTjR28Uky1S0RHiRNuvBHxYllmlC1OdAs7gQq8GgfKYmDGXlyEnkc7jA5EhA5nlw2dGgq0FQXadHfBWFVehAztXVOl1kuT0TmqPjWgMymEzShlkg2uIg1agAys2VKwQztfkShqqw9Ymw+YHw6UFQnVcHPTXlqfMSXnLBRppg5ooA2lHAuHFQtCZAo3WArEHAbkb27tb2ycxkt5mj6kNitOhg1Gagu1IwqsGwozfgDTamqa0kFvxRFkshHAIw+RHA2NFgvQFATcX1mlzlGNrUlhoSBIgA3LJgxJbwvoXlVakCNvsSChKBlepw9biw1GewzOIAikNAaQpFDdVUzkTkDDQjXfRDN7ti/DMyLYKRFMkBBxPw5jVgyOTQniYFmZuFB+qjp3nzmKxjWzNyh+wieDLhB8VwqYPAjXRzloniraNiNeaA6FVgqyTg/pAAAAPnRSTlMAId7eGQZcshnuQZeI+FjUxp1yDfvyrDIm26WNf35jJfTp0cJNQTIO6bmebUwThXddUEU7+3RHKN+OKvnljHQ4FTYAAAwuSURBVHja7FldSFNxHN1LKAg+lNF39PkSPVUPPZkXWuDqTiTSq9M1l+3eLa+bW9vUaEuLGrkxRltZbUuZieFgsWCZgcL6EBQfNHvIiqLvKPqCou86//+2rNe4t6eOCLKXc+455/f7/3dV/Md//Md//C1m5c9fv2pVYeGqVevnz5ml+EfIL1y0sGD2unWFi1YuWFZUxFAUFS1bkbd41fqliwrWFMxem6+QD4ULWJfLxYgi4/L4fYDf42JyyP7FLliikAtL5/r7Q14P6x/09vf3e0fiEMCwLMdxoiBwHAsNnMixfIFMicyb6wv2hvyukWQyCfpBn58X3G51Fm61W2CZVMqt5vilClmwhA1FnrwQR8Aej/t8HtCDWKez2zUaTb3GrlOruZQyPalm8hSyIM/fe6nyA+v1gt2fo8/xE2h0bldYNWbnVtAMZBGgf8b54rmHBz3lBz2FXSe60h1jGrkELOGDl/RP74keD8O5c+w5ehqBwA8p62J2uSIoFJKRO5Vf7nEsmi+ifpSfwg4xajfHDtV1FA+r2dkKWZC/fDB6s9LQ8CJFFAiZCSDMaB9GQGRS4ZoOZY9dWDZPIQ8WutBCg9XybWLIRV0QoAK/IsDdS0yUOFVKZUzDrpyjkAdLmVBUbzQ3aC+XPAwnYliKLO9yYSve+/Dsy3Nt7eayGmXVDR0v2yrM86CFlYZ9WpOj1AmydHgsJnL+3vGDh1r11p2OElWHsviGmkcFZMFqzhu92YwMqnfWbi4pU9UolR3lKS509sruQ53GhqbSEpWyrv2ihl0gz3k0K48PRvqakYGlzVZKBdTVhSdHBs7uPnKo0WAxZQT0aNTMIunZ6VEwErnZSAQ0IIPNJcSB8pgnevYqBDQbLC2bIaC9fM/Fem75fIUMKGCCkTtUwL7qpkwGHWMiCWD3wVa9udqGDhIBsIBfrJAe8+diCzRCAFpYvdNW6ixRqdKTgwiACrBqswKqqi7Wy9KC2UIIBswIIBYM8SQAJNBZadXW5gT01KtlOJDnrMRR1NmYjWBnC0pQEhaTCAAGYAj2tdU6MwKKi29gF+E4krqC3sjbPwRsrkn5x0kARw62NhsbdkKAigqoGqoX+NVSC1iMCjaCvw97oAECaktLR8UgAqAJ6A2WjIC68j3FxeFhO79GagErfNFLRICeHAZaCHA8nIwPZA1orDRXNzkgoAMCYEGsnpO6hvOE/shbagASsGib4ECC7aUNxB7uM+6rNjmcZBVTAT0ad9EqaQUs4TADzc0wwIgE2iDgIdc/cIUGAAPIbiKDSRdBMWpoZwok5afXMfD36Y00AZOtNjeCGIE+o9XS1oLBJNuZCkAGyyWdg/yN8ehN8KMBNAGTbZoYAH4Y0AwDspshI4BmIO0crOP6o3f0egRgyCRgS/DRgat4/oOtnXqjFZqIANpCDCLmQOJbwWxcRQg/rSASaJnmvANXjhxBABkD2ky1VEB2FVVd1HCS3kwX4ipSCRgN5gYi4PIo2ztwlfI36kkr0MqMA7SFZBeJKyS8mM1a4Qs+IfxGM03g8stUfBwGIAA00Ew+shEBMy3s0QjL50l4EMyNB58YAQNNoOnyhBgauHrwIDEAZxMdC8eMAFICu5pfK+FRLIwEnxiMBgMxgFRgyBMZp/xooDmzF6iAspyA4mEds1TC26DgDT41EP59hM30ctI7fuXQoUOtvwxAAlSAKicAq0jCW8laIsBsJvwWCCAJjLdS/r6sATY48IeAixopd2GhCAFWq3UfDCAVSHh6x1uBTnJHpgaA/88IIGCNpAJCz8HeAANA9zI2GLnZ2drZ2ZhrQE6AakZAPbNQQgHCSPK5BQA/GUIXLiczZzNKSfmdSCAzhpI7sJobTD6vBrTaNiQwzSajfXp9n54sRlJK228C2n8JWCThGBb5vN+0YG8Dv+nyBBvqrQQIPyllxgBagcxZAAxLOgVzlvvjL3YCTU0mU4ttlA/1GgjMtJRZA7CJZyoQ1qmZQoV0WOkZfGECWlpI3xJ8KGglyPDTJYQAfk8A5/Gy9ZJeSf33bDZbLeBwlCb45LMGwGL5/flzBkAADiOJb4VrWY/noQNEhAoC+p/lGkl3YO75O7IJ0K8GedLeiBh2FDxgws8oH//QRgvRkqWn/Crw09sAbkR2qd8SrGHZVA2ek8A5wfoGTaQN1Hz6aRn4EUC2AbiXi8vypb2WFzFiguRMUI5X1dPk0YEZevr8CIDOgA57UFosZFgu7QQRoIzxfMJBuJ2bp6fphzU1yhw/cBEGSP3dbP5cRnCVo2h40poxlnU9hB/Osh/d3W9I+KCvK8/yV43hJclCyb+dzmZZd0wJLiDtYoQx4vynruMVXW9qwE4eH/kT9Ojs7HIZXhAUMJw7lkbSU1NTsEAYLSt703Xswo5A15upuvL28vY97XAAEzBcLxbJ8cJ+Th7DqcXwVPrR50eJFDMphidubT3ztXtv4Nbo1FR7cfjR58+jVYRfYBYhAOmRTxQMx74HAju6T31/9fHG667rj9/fP7C361P60acN3d0VFbce9ejAX6CQB3MK0INXgZPb7x4PBLoevH6w9cy7bSdub9p1a0MAZdix5XDX62GNKNu/bIAlc5lXp7c/PnNyx5ZdgYrAhTPXzh09v+lwRcXdkxe6d+0/UPFax+EeICPm/WzHfF7ThgI4/mpTh6KoG8huPQxcS7e1G/vBfhF4QhTcYWy+/APvX8jRQC4JNIeQGlA0h04voqAo1ZuCHpQKxcoOW0dZaQe7FLrD2tEddtiLdkyQwRjkucE+EHL8fvJ+5cu79BUZm93uQUoR8MbWWbfUqiZFfqt3dnB4lBRefXpNrujs5c4Tfuu0VtQOPyjQyJS1fDUp8GfdgdaKsnLu67UbwG48G7ncQbmsN9+hVGpYT2RZOfWmdp4vtKWNu5evANu56kIy11Dr+UQO4u1KVRLRXumgUuh35Ff3AA3uvUKCkK2Gw9s8FrJtluOHrQJ5K3D5OqDCU2LAsu1+H0GhQ/Jz2bbUkWToZwAdFu55IVZEiRV4LGLysJIgIxhkADXmAj4IIULINOEY1/J9QBXG7XGljL3jg8b2Oxm5VkKAOsx87OWLZ5FmOMpyDgbQZ24s8HwkMAco82uBB/fXPIFAwLPqDE1tSvsFmNXleRPBMV7/CpjEfoEHD71mKmYYRiwFMSfLGC6CCewWuL6yZMa2MoRve3uNkw8iq/A0BZhlM5bp9U5ffIlEyuV1tUKKim+ymdgrwDB++L63+bY7eDYolSLldD6cFKEHTGCrgM/thxkSXyyS/EhZI/mkHXjdYAq7RsBn5b+pFQelsrYeT7fC4baE/FMzYJsAqYej/FJ5PR6P6/VEItpReCeYxF4BY5yvjfLVSriQlJCP2kEk4VTv44/8XV3NhxP7Hdk7NQC2CQhkAj7XauP8dL0STmQ7AgyAKewSIAPwtki+f1dPW1WR5LMinJ86hGwT2N54//JFRFObzVa+QuILfVZErqktaKMANIyh2qokLMLVbJIVIIX8SQEkK/3+fjYaze63JVbkoINC/qTAuKKOkAQOegO2zv/0IhQRz0OEOY7DGPGugM2fPy3Q4RzO1aDf5/D5lgNOKvVw+m8IwALDML999v17pfTmg9u319bczMJMBB55/EuPd3ZMhLyO4EqIusDNJRizimYOIqvwuoL3KQuEdjIfN3sv3xsnPMYcJhbBEN0RcBmbn990v5zr6eHhCVZkDF2rVNdAEGZOa7VixGpb+rDxQVAQ6ZsMPYHbOynjfDAgApoW19P1bUHEvIeiAFmFZmNd09YtiIHaECTMB3z0zoFbJkJDK3yErtaPRGLgpSfwaAnhEz3+06B5REonpHgSPjSR3NB34xek1Va1I9AUuOk3Oe4wndbHArvpZqVPyvgWNQGyEaAiN1SVOOyOq3chKaIYPQFwawcpylGr2azXVdXqvtYVLTymJ2AZCOL+USWfr4zrJxkCc4+iADGAiiT1s9VqoVCtRrNtVuIaNAXA2vwGFkj3TBLIS1Iw1REgMJ55iLAiEKw/EuQNimtgzNxK0OHlCV6XP+iazT3hwqLb6XSHri/8rReVv+S/gB0CmeOIlp+hQCo21JuJxOwEIGq0CoXCrAQWHUhW2klCR3YsAvowREAQR2AHA2aAB/IXkJI+E9zOC9zgP3/Od9g51BFcCJb+AAAAAElFTkSuQmCC",lH="/assets/093_\u51CB\u8C22.aa715ee6.png",sH="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAADAFBMVEUAAAD4+PhuZ2D////8/Pw/JhF3d3d5eXk7IAlxZVp3d3d6eHd/fHrd3d2Xl5dCKhOBgYGYmJg5HwuYmJhnZ2c9JBBsamhWPSPu7u5NMxXGx8daPRs7IxFaWlplZWVaWlpCKROXl5ZoaGhaWlpDKhVdXV2GhoVBKRZiYmKNjY17e3tHMB1AKBN9fXxbPhs8JRJ0dHTCwsJXPCA/JxKkpKS1tbV3dHFnZ2djY2NBJxG6urpBJxE+JhJ5eXlaWlrW1taDg4PZ2dmdnZ11dXXb29tjY2NGLBRiYmKNjY2SkpKRkZFILhW9vb3CwsJfXFnPz8+hoaE6IxHBwcHj4+PS0tJycnKUlJR0dHS6urpmZmZ3d3d1dXXHx8dbW1tmZmaJiYmDg4NAJhLq6upHLRRiYmK7u7uOjo6fn5+WlpZzc3OamprHx8dZPBo7IxF9fX03Hgo6IhF9fX1fUkhzc3PIyMjFxcVgYGCGhoZ0dHTNzc12dna6urq5ubm6urq6urpiYmJ/f39jY2Pt7e1ZWVnV1dX///9dTD6dnZ3Dw8NOMBecnJzMzMzFxcXOzs6bm5utra3Hx8fKysqZmZmgoKB2dnZxcXGXl5eUlJRMLhaPj4/Jycm3t7dBKBOMjY15eXmqqqpzc3Nra2thYWHBwcGsrKyKi4ujo6N/f39GKxQ4IhCBgYFwcHBtbW2WlpZNLxbPz8+np6eTk5OHh4c1IA8lFwqRkZFSMxg/JhK5ubmFhYUuHA11dXU7JBEoGQumpqaSkpJmZmZUNhhKLhVILBW7u7uioqKDXyeAXSVEKhMyHw4sGww6IAuzs7N9fX14eHhjY2NbPBqDg4NZWVlgQRwhFAm9vb2EhIR/fn5cXFyDYCZKLRQ9Igx7e3toRx5YORmwsLCpqamJiYloaGiCXyZ9WiV7VyR3VCM9JRF8fHxeXl5vTSBkRB7W1tbR0dG/v79zUiHAwMBsSyDT09O1tbVxUCF7dXBwYFHQ0NBzZlqEb089KhxMMhl3bGN2aV5dRy6DXyjjKJ9PAAAAh3RSTlMACQRHaMNDJPRTMBcKBewnEOLc29vTPh4cFhQL9O/u5OLQxsG2sa+qpJiLfnBkVlBPTUREMiUc/Pf39u/o59LGwr+7trKYko+Gem9kY1ZKREM4NScZ+PPu7Obe0s63tKahnJuHgnFkY1xWVD44+fXz7+7l4d/X1tXCuJ2Zj4R9e3p5eG9rVjchCw8JAAAJT0lEQVR42uyXzWvTYBzH4w4KU8GDDBFUUBQdDDypF0UQ8eUgHhRRUTyIbwdBBBUvKh42sjbb0iSllsS8WANtRFMorARsD92tTWmhL4fBbE/tZQz8B3yeNlnmo1ieZ02L0O8/8Pn8fkme7xNqlFFGGWWU/ydj1FBz5fCh99QQc2VfuV6+MLwlTOwrF5v18vlhGUwcKKuGAQzubKeGkW0vIN9IAINDJ6jBZ/uhspqQLU7mlXb9zDZqIEH5nKTrNcky2uWBG+y6A/mFdCzWiC9bCbV+ZpwaZHYdrgN+LS1mzIxYakGDA4M02AH4cH4xLLCCKaZbXKLYPjBBDSpjR+uqwbWqYphlaEYIi+lCx2ArRRhyPkuDsB0DPtved5waSM63AX+5KpoCQ9PTNNxBJNk1eEz5n7EL63wW8KehAQsMdI5vquobyvfcV1VDlkqxjMBAPmpwn/I571RVsSDfmX+jgS0rqupzOT4+VVRkKb4+v2fwJdLQJVkpqr6W43HAtyDfm98zSDXiwCBbPLqD8itb93fnT3nzewqOgeGbAeRnIb+R+uLOjxrEOgbZu7soPzJ+E/BtvZHy9o8YCBnXwI8ryvjuDj8ZQeZHDEqgHJvZg9t94DcVnuvwGZTvvYpCRoQGSvZgvy8I23rx3R2YYrUFDJq7J/rMVwC/loyEUT66A9dAudnPcjxxUDHW+YgAYuBcEHhD2d+/ctzb5acjYQHlo6HdCwI0eNQn/pbDgA8vQD3md3cAiiFdAwZG8UF/BI5lOVsGfHf+XgqMY5BInOqHwc5jKhdaKsV7z4+UIzQoXt68wMWiHZpb+RRGCuDfCq4Bf/LSZvmXOvx8Lhpie/CRcgQGNs/zyuTm+JdPSqG5uXy0oq19YxFOrx00OgaJyU3xsw5/TZvRfjAYAoxTjrzMvyYvx4fO/Lk1TdNmZj4xWDtwDeRzpNU0lZBCKyuAvwr5IHM0jbMDwTGwXp0gu4Bcl5by+Z+Lle78MCs9Df6sZ5m3uNtE5Xiu8H0xGs1VNIcPEshP4+0gI0IDjszgXCy6Wll12K7Bz14GaDl2Dexb4wSPwDYXA4H5hYX5wAaDaAjXoLps8ZxEYjBlmblZEGAQ8AxyIQbTIF0ABsuntxJ8htfNytcgMPgwv9FgCceAdqqJa5EYPOLNSjAYRAwqn/F2AAwKHG8XnhFcUZ7cMHPBr6jB6nfHAKscudrTKRKDcG4WPobfXkXtG+4OoIGt62/xDa6eDi/+YRDQPhLtQNcnx/ANnqdQA+dYJjCIxycJdvAy4hg4XyPesez9v8dtYFC6h//vuuds5C87COQxisH9fyc2SEUX/mKAdSyDHYBytKR49Qj+BeFa1yA4+wE5lhnMcqzWpEKVxGDvkYy7A/JiYMHnGEuXksnkFEVg8KtdMwltIgrj+LgEFLHFSq3bQUHwoCiu4AKiiBc3XBAPgqh4UlFED+JyELVJO00nDbRpMsWDScgcmrZMmilhRkmiWaYeAi1IKq2FpA3UxGrVui/vzaKdN63JTC8e5n8Qb//f93/ffN97bTtcBMgAIegCGWicCM3Nnparh3S8j053uJxoBnAsl5yB3f7M+8ze0NDp8fy8vE4PQZOLEBeDguCxtVR/b/vgYLu31eP5kk1dWqPnjSQQoBm8LXEsA/+Hbnd9TYvnSzwW7ydXL9FFgNehfQDv66XV766vr7e3tIz3D8djmRGfqVzHO60VEtTCU5i4mh7WlFQ/9G9uGQ+m+kfjsfSwpWKjTgKIQOCKxWAtYi/5e5ubx/2WYOr1h+yv9NDAlf063opPXHhtG5qB+dW/h6Ls39n52e+3WIIDPSNDsXS8h923TDPBgRMu8yQZgLFctP7HnU8Ef4Hg3VAmltHVihsggZABgZd2X5f9Ozp+AH9R4R7YiukPkcqL2gnKxAzQxVBtnbp+8AG0NzV9h/4yAWjFLGjF4HLtM+lCWZcZrGc0g67JF4Ps39r00eGQ3MVjAK2YiWVTy9dqJ1gACOSRhNzX1fP3MfQfbGz8+M03AUBqxQxoRUZ7Kx5dgGSA3tfR+qH/15c+h19BEO55NxxPZ94lTFWaCRYiGUxxX5frb2h88ZWjyChKkBKm4qhDeysekwhs6sWg9n/Y0LpydTefzCX6HBaFwnAmxdJD4Z2aW3HLyqdIBtJYtqr9ra0rl86roHia8UUQAtCKcCZlU7lzeghs6lN45K5B/asbF27BsLnbkjxFKtvg70yKv2bOaG3F43tkAnQx1Kj9gda8DIVYMip9i2grwvVYNQ0Cs+rFYLcL/m5744LN4i/dV7G8QGBBFBbX4+g3zetx6Z4uNAP5vg79BwX/hoXQH6qqguJgI0qngLZifDiseSrOv+nCneoM8Pf2apC/6A/ql7VxTpKjmYTUiOhMimdHw8s3aiW49d4sEyjGstcL669/Zv3rL7YBIPBJHyPaCEOj/RGT5sfr7UkzIN64hQtATdlRbKLO5Hiekj9GdCaNjPQEGe13lDsCQZ0iA5yoJV65of9h5K8/TCzHU6SCoM/XJzXC61SUXKX9/X6+SyJw4n/8bbVtxHNvNfBHtLWC5UIKgkR3d3dCIBgYCCaYneWYdgIXTsgZiP5O8LO1Ory97CCm0qI5lIKgrxtKyCBocSRYchOmXQe2yxkQuFg/kBN/cw+bRHPn0BMJogKAT/i/P0JS5HpMDwHIQCaA9UN/86Oz9xdPQRCABOI8iLyEikB/hyPK0PoAsIPbCUJcTU6bTfQ37509awY2FQFPyfPAB/zFABzRBJsER6CXwAkIIAOUDUf81QR0LiHuBYc0Fvx9PiZJryjH9GnDSYKoa2srFAqf6or4iwRckgWNIE5lKQCSClHgM9RNADqxMJYfK3yyEebdiD9KsIMKBJLgGOQ7EgyCZJM8sxbTrcPXcGchn8+P1Rbxh3pQmePAMYAQRAQ/bACao3dUYfp17LrZNpbPFwjzLtRfrSWryVAvF6JZJuGLRqJRH6if40khAP0Ep3BbfkzyL6pz26gARKDYHMPkKDoUCLCmZdi0tBgQOCX/4tpUyYR6ewN8KAkU4np7KeQT0ENwA1ecf5FjWLMjFwoABiDwL7XiCDZtzbh7FvqXqiP7VjA0D905mjQh9evULA3+MIW1qyq3kSS507QfOX+9mj8f06iqI+vXbyqfiRkyZMiQIUOGDBkyZOg/0m/+aqodh3mGTQAAAABJRU5ErkJggg==",cH="/assets/095_\u70B8\u5F39.3dffd8e8.png",uH="/assets/096_\u4FBF\u4FBF.b0d5c50c.png",dH="/assets/097_\u6708\u4EAE.47389834.png",fH="/assets/098_\u592A\u9633.89c3d0ab.png",vH="/assets/099_\u5E86\u795D.2d9e8f8a.png",pH="/assets/100_\u793C\u7269.37ae5ec0.png",gH="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAC7lBMVEUAAADONgnVOQm5LQzLOSbHOCe8Lgy8LgvBMAvGMgvLNArRNwrONgq/LwzsvrHFMQzBMRTTOAm5LQy6LQzVOQjVOAfUOAnFMxO5LQzBMA7SORTBMAvUOQm6LQzVOQi6LQzUNwnMNQrUOQm5LQvfkYPdjnmzJyC3KSK1JyH0h0jPNzLRODO/LSe7KyXzgEf0ikjDMCnLNS/SOTS5LQvxbUbHMy3JNC7BLynyd0b0gke9LCa5KiT0hEfzfUfTOjTydEbze0fUOzXVOzbDLSfwZkXwY0XwYEXVOQnNNjDFMivEMCrwXUTNNzHyekfxcEbxckbWPDbya0bVOAi2KhTXPQ742Sn0jEjxakXwaEXziEbuW0TTQTPwXES7LQzTPzO+LwvBMAzLNAvXPDe8LgvUQzPGLinRPjLHMgnTNgf51yj40ifcdzzdejvROjLFMQn750fvWUT51SfBKiXONxXefTvIMCvCLCbQNwvRPDK/LwvJMwr52i3LMy363Sj5qxv52y/JNCz52yn5zyX4uiDRNQXKMSz5zCT4nhf640DLOC35xiP5vyHDMAnBMAnbdDz63zbCLyjLNCW3KRr4mRbKMg3IMQ3MMQzKMgX0ySzPNyfFMQ385UPonjXiWzT63zLOOi/2jkrnUj/bSDfWRDTWSjLuszDywSz5wyL5sRz5lBLPNAvONAXSOSjKMxTNNgv85j3hTjv74TrmlzbfYiz5yST4phq+IwDrV0HfSzrYTzHIMyv63yj5tB74oxjlWT7ggzniUjTjVzP98Ev97EXxfETrXkHYPTniiDjjjjbrqTL2zivFMiL4tx+8LB3uWEPbcDzwuTT30irBLx+4KxDzg0XhVDvsrDHqozHpkCrkbibofSXvmiTrdB/wfRn0yEXub0Hur0D85jbZWjT63i3zxSzfWSnrYz/0yDvlkTfpazPmZDPTPjLjfi/74ijgTCjvgx31jBbziUbxvkT42j3vqym7KyTdSR7ifzf21DX1rSG5JTuyAAAAJnRSTlMAC1+6U1PzU/T09PT0UlMsAvWa+O/evkKybCEK0sitiHhJiWBTU1yGCb8AAAkaSURBVHja7NMxasNAEIXhyLhLYQUkmTjG2OnUaFsJJKRuKiUgFoFvsL0KXcBncGfY2rcQ6AjqVSUQFwY3qTM5wY5gBxLwd4H3L8s83P1Zq93Mpt3CnbLuzjc+2OUFW4f++gBQZRMgf0bcX/i4riqQFoFSmEArcPD9Sl4/42F/u+2tGPqxk1jgLSkBr7j/PQqta4u0jq9YsHYIH+DhfqJrYZlOfwu25oBnqGSvhX26lAoC13iBG1AfgoXuFPgrU8DLGg5fOuRQj3jaS+MNeGwBosfrnhsDnhRPABqkogVcRGjAHpByCAegBZwvYcoiIgYcT2HCIY1aegCLrGkJAY/t8ZRGHJK+aQ//JCCJWEwIyDhMCIgyFiU9oOAwISArWMTNmRpQsqAHFDGHMucJoHsnB5Q5B3pAF+cs3sgBP8TOPUvDQBzH8V18JbpmdzDJEqhkkIREDgrxFg2CohyIOAndglBxSElp0kmtl6tDW4f4EILi0i7BrbYV2g6d2kFH+zAo1KYntPhd7pYf/8/K2lx6owIsXicfVmJzidm7uKQDxJh5FJP+GcDI1ABGpInpN3pEqqgBZ/eMRJEoNwMvDEPPa8qiSLNg9+KUAFGeliQHoe0AiBCC0LFdj5WkqaM/ANjoZDkoqgDpSyBbymrLywiqtsfKU1YzBHCuBnXQuKt1q9Vqt9a+0XSk2gE7bUYNYLmo2MCGSC3XEv7jKH+n+lTSoeZx0TsuNxuA5wC9UTP9ne98v7UNkOrykcOAGsDxk+M8FcCPnm+aPwCm6eNUFoEiHxEtIB4NKDgQtDFOmP0So0ZfXCnpahgFEKgAC/HkVUbghQkpNoDPdUISGGNCjGEEDxikXslCrTBhyfNCxsnFz6kAp/toEoF3gd6xDEJwK1+xjg8HHVuf+VQPE6P+CoCj/H5eKaY39+kBu6tpVxE2xhIKGmq8WH2BkSpvV47Whx3my1utumFY7x1ddYXxlZJxbg92V0/oAV+klE9r2nAYx0877K3oab6AQJKLZZdcvJgQqERFfxFMqUWqqcZQoQru0oEFqfin1sMOxbZoteBt1VJsvVhbb2sPg663XXbb88SsqXQb6fY9GBB/+X6eT57IsitrW9W28F7wLkToBALXj6kUlF3JpF/UsF8bEtJK7X7YTd0VTwK10fMz4ENoV8twO5b1I8AbWwBLLIsI/oeDtrBwu3YtchjWQDqUTQgZjIFA3ZPJ2fkdfudRpxG+4rUCs3ci/jWstwDsGcDAwbR40I4KQnQe7wEfmKqhRCqVSng8JRgc5r/vk9WGmkjgd1qjHqh6oxCw5Y1WquXuygprxp+0DZD0s2bgePehUxmZCNVAvREOeRLYr42/EnKtjgdE3oNlQIBQWLmJSG34oRCtHNS2WHN2CApw2wRY33EkY35kMD2sxNwiQIyEUS1+mA0r0GY8+2IfuktAoRmrmPAoYWUa4CujSqdW7mK51e7fTDqc2zYBPjFONyBYx9fQY/qh2pEi3zIZUID1qvqI9mXS0nrm66BkMt8lXkyDOWy36mNYT3PLdgE+cxQgbKKFBYolyTXNoAIcfzgcTgayLK+WJsPJOfaHwpmsLklb+NQXh3c7XDTn45bX7QL4fAztciRBwwJCWorPskcZJQRlgwIhRDZCSKGkGgDZXL7Ol5+rj8WS7xxOiuE4n12A9SAAQDhAAA24DRaAODvKZY1nUJJXMWAAP4ca9CuZo339hC8/taN6t9NFMz7IawHwAEPNGQDiyUBu/yiMCpQiplXoN/CK8xsCLtDAUznMTjMw+6sBOCM+jmNoyulwv9sEEQDRlSLTfD4HaxjyaD3MdeFs/NiDJTQF5H9IfBnFYzvOju4583bMKwCsMAxFuQAiCSbSfPxW1+cKxg1Mi/Sv7huNe8XcAH0GAEa5k6KgfSG0LYC3FoAVWEmXw+F2i+Lh6YWhwNOaP/xfO6DON0C/FfnIy3ITYHs9aA/Ax7wIzdBgQuTrx0CACgaXBQhZlfFyWVJBwL5+2jyM8xRNM7/NPwNYoXnxttnU9+FFKO5hBqQ/wes5/Afk8qfNWV0UGcj/AASDO38EYPjAl+ONpo6voqapqlqCJeypqjbv39i4ifN/AfgYtAnwk9o6Zm0biAI4PrZL+yna5W45CaRuBnfSHVozHQgNQpsF3qJFqDFYKFVA5aaGgpfQ2GuNCjbRXEgDhW4GZfRsD/0AfRIxmWQd2EfwfzGa3s86PaGP/bYcuAVRI2h28QwA959gAZ7mixsHTqCt3hEAA+4sRFFMYRUugNAAzoZDWIDRXVSU8AScHw4I9gDwhPvzpCymsAtjIHz78+t+eDG+vB1Ni7KEFfBRfx8gkAT02tI1n/urJCkjINxejr//+DeG1w/8/TJJNp7DU9RrTT8YAFkx585KNIS7h9FnGD56mEZFIpLNjeOlpt5rbXAMAKa1YL4VAg4iaoKzT4SYVR7Mp1bvYEAQfO3r7WnEAMGimgkoaRIwfrN2OE/JEuvtDa6D7HAANvKl7znOutrOdm0f514zn9q6YgBk05ylHAiL9ap6hKr5wvO551NCNP04AB3vS6M5oRMg+A73IA6/3E9ZTmKE9yULyDoAA40RQmh6znf5kyXJCVsirBqwE1BCcpgYp3VxfUXgCuEjAb50ADDSDEagHIJIHTUR7ghJAV5nVwDoyjYpI88xGlsIdwOyKzkARl3VH4oGZQwUjFHDtJBE9nX2850kQCbb1kwzjk3NthGSBbztBrg1QEUAcE8FgGwlWfIAS0nyAEtTkysJ+P3iAM1UUiwNMJuUAN5LAQxFua776qUBb6QAVFHyAKYmOUAY/mVETWEYngjgg6JOA/C/XTpGYRAIojA8IphKlLVQEbEIGAtTTRGIx7B+bLE38l422bOkT9IHdosdZMHvBD+Pl2n9eswytNaXKAL22UE84CkknoC7kKMD3pEEGLMvQowxXgHb4iAecBNyBkQSALNNQgD4BEAy4NAFxngCRhlxBHQZWDIgJ4cyBa+jjA3ICnIZADvKWBl9Qi41S02wMaDIqUsBSLxgsoyqILe6AhB+g9UyMJCPln/sGpK1/NUk5OWasQhVkqdCVRxa1edE/pKLatJwGtUWJZ3++QAvYm03quwEIQAAAABJRU5ErkJggg==",hH="/assets/102_\u767C.f43fee5c.png",mH="/assets/103_\u798F.58c94555.png",yH="/assets/104_\u70DF\u82B1.61568e1e.png",bH="/assets/105_\u7206\u7AF9.35531687.png",SH="/assets/106_\u732A\u5934.7eb8ff1d.png",CH="/assets/107_\u8DF3\u8DF3.24101efa.png",xH="/assets/108_\u53D1\u6296.3eabd306.png",wH="/assets/109_\u8F6C\u5708.67669ca4.png",m1={"[\u5FAE\u7B11]":w9,"[\u6487\u5634]":$9,"[\u8272]":E9,"[\u53D1\u5446]":M9,"[\u5F97\u610F]":O9,"[\u6D41\u6CEA]":R9,"[\u5BB3\u7F9E]":I9,"[\u95ED\u5634]":P9,"[\u7761]":T9,"[\u5927\u54ED]":N9,"[\u5C34\u5C2C]":_9,"[\u53D1\u6012]":A9,"[\u8C03\u76AE]":D9,"[\u5472\u7259]":L9,"[\u60CA\u8BB6]":z9,"[\u96BE\u8FC7]":F9,"[\u56E7]":k9,"[\u6293\u72C2]":B9,"[\u5410]":j9,"[\u5077\u7B11]":H9,"[\u6109\u5FEB]":W9,"[\u767D\u773C]":V9,"[\u50B2\u6162]":U9,"[\u56F0]":Y9,"[\u60CA\u6050]":G9,"[\u61A8\u7B11]":K9,"[\u60A0\u95F2]":q9,"[\u5492\u9A82]":X9,"[\u7591\u95EE]":Q9,"[\u5618]":Z9,"[\u6655]":J9,"[\u8870]":ej,"[\u9AB7\u9AC5]":tj,"[\u6572\u6253]":nj,"[\u518D\u89C1]":rj,"[\u64E6\u6C57]":oj,"[\u62A0\u9F3B]":ij,"[\u9F13\u638C]":aj,"[\u574F\u7B11]":lj,"[\u53F3\u54FC\u54FC]":sj,"[\u9119\u89C6]":cj,"[\u59D4\u5C48]":uj,"[\u5FEB\u54ED\u4E86]":dj,"[\u9634\u9669]":fj,"[\u4EB2\u4EB2]":vj,"[\u53EF\u601C]":pj,"[\u7B11\u8138]":gj,"[\u751F\u75C5]":hj,"[\u8138\u7EA2]":mj,"[\u7834\u6D95\u4E3A\u7B11]":yj,"[\u6050\u60E7]":bj,"[\u5931\u671B]":Sj,"[\u65E0\u8BED]":Cj,"[\u563F\u54C8]":xj,"[\u6342\u8138]":wj,"[\u5978\u7B11]":$j,"[\u673A\u667A]":Ej,"[\u76B1\u7709]":Mj,"[\u8036]":Oj,"[\u5403\u74DC]":Rj,"[\u52A0\u6CB9]":Ij,"[\u6C57]":Pj,"[\u5929\u554A]":Tj,"[Emm]":Nj,"[\u793E\u4F1A\u793E\u4F1A]":_j,"[\u65FA\u67F4]":Aj,"[\u597D\u7684]":Dj,"[\u6253\u8138]":Lj,"[\u54C7]":zj,"[\u7FFB\u767D\u773C]":Fj,"[666]":kj,"[\u8BA9\u6211\u770B\u770B]":Bj,"[\u53F9\u6C14]":jj,"[\u82E6\u6DA9]":Hj,"[\u88C2\u5F00]":Wj,"[\u5634\u5507]":Vj,"[\u7231\u5FC3]":Uj,"[\u5FC3\u788E]":Yj,"[\u62E5\u62B1]":Gj,"[\u5F3A]":Kj,"[\u5F31]":qj,"[\u63E1\u624B]":Xj,"[\u80DC\u5229]":Qj,"[\u62B1\u62F3]":Zj,"[\u52FE\u5F15]":Jj,"[\u62F3\u5934]":eH,"[OK]":tH,"[\u5408\u5341]":nH,"[\u5564\u9152]":rH,"[\u5496\u5561]":oH,"[\u86CB\u7CD5]":iH,"[\u73AB\u7470]":aH,"[\u51CB\u8C22]":lH,"[\u83DC\u5200]":sH,"[\u70B8\u5F39]":cH,"[\u4FBF\u4FBF]":uH,"[\u6708\u4EAE]":dH,"[\u592A\u9633]":fH,"[\u5E86\u795D]":vH,"[\u793C\u7269]":pH,"[\u7EA2\u5305]":gH,"[\u767C]":hH,"[\u798F]":mH,"[\u70DF\u82B1]":yH,"[\u7206\u7AF9]":bH,"[\u732A\u5934]":SH,"[\u8DF3\u8DF3]":CH,"[\u53D1\u6296]":xH,"[\u8F6C\u5708]":wH},$H=e=>{const t=Object.keys(e).map(n=>n.replace(/[\[\]]/g,"\\$&"));return new RegExp(t.join("|"),"g")},EH=(e,t,n)=>{const r=[];let o=0;e.replace(n,(a,l)=>(o{typeof a=="string"?a.split(` +`).forEach((c,u)=>{u>0&&i.push(C("br",{},`${l}-${u}`)),i.push(c)}):i.push(a)}),i};function Dm(e){const t=f.exports.useMemo(()=>$H(m1),[]),[n,r]=f.exports.useState([]);return f.exports.useEffect(()=>{const o=EH(e.text,m1,t);r(o)},[e.text,t]),C(m$,{className:"CardMessageText "+e.className,size:"small",children:C(Tt,{children:n})})}const MH=e=>!!e&&e[0]==="o",y1=Gn.exports.unstable_batchedUpdates||(e=>e()),aa=(e,t,n=1e-4)=>Math.abs(e-t)e===!0||!!(e&&e[t]),kr=(e,t)=>typeof e=="function"?e(t):e,Lm=(e,t)=>(t&&Object.keys(t).forEach(n=>{const r=e[n],o=t[n];typeof o=="function"&&r?e[n]=(...i)=>{o(...i),r(...i)}:e[n]=o}),e),OH=e=>{if(typeof e!="string")return{top:0,right:0,bottom:0,left:0};const t=e.trim().split(/\s+/,4).map(parseFloat),n=isNaN(t[0])?0:t[0],r=isNaN(t[1])?n:t[1];return{top:n,right:r,bottom:isNaN(t[2])?n:t[2],left:isNaN(t[3])?r:t[3]}},Pv=e=>{for(;e;){if(e=e.parentNode,!e||e===document.body||!e.parentNode)return;const{overflow:t,overflowX:n,overflowY:r}=getComputedStyle(e);if(/auto|scroll|overlay|hidden/.test(t+r+n))return e}};function z$(e,t){return{"aria-disabled":e||void 0,tabIndex:t?0:-1}}function b1(e,t){for(let n=0;nf.exports.useMemo(()=>{const o=t?`${e}__${t}`:e;let i=o;n&&Object.keys(n).forEach(l=>{const s=n[l];s&&(i+=` ${o}--${s===!0?l:`${l}-${s}`}`)});let a=typeof r=="function"?r(n):r;return typeof a=="string"&&(a=a.trim(),a&&(i+=` ${a}`)),i},[e,t,n,r]),RH="szh-menu-container",du="szh-menu",IH="arrow",PH="item",F$=f.exports.createContext(),k$=f.exports.createContext({}),S1=f.exports.createContext({}),B$=f.exports.createContext({}),TH=f.exports.createContext({}),zm=f.exports.createContext({}),co=Object.freeze({ENTER:"Enter",ESC:"Escape",SPACE:" ",HOME:"Home",END:"End",LEFT:"ArrowLeft",RIGHT:"ArrowRight",UP:"ArrowUp",DOWN:"ArrowDown"}),rn=Object.freeze({RESET:0,SET:1,UNSET:2,INCREASE:3,DECREASE:4,FIRST:5,LAST:6,SET_INDEX:7}),Ns=Object.freeze({CLICK:"click",CANCEL:"cancel",BLUR:"blur",SCROLL:"scroll"}),C1=Object.freeze({FIRST:"first",LAST:"last"}),Tv="absolute",NH="presentation",j$="menuitem",x1={"aria-hidden":!0,role:j$},_H=({className:e,containerRef:t,containerProps:n,children:r,isOpen:o,theming:i,transition:a,onClose:l})=>{const s=_g(a,"item");return C("div",{...Lm({onKeyDown:({key:d})=>{switch(d){case co.ESC:kr(l,{key:d,reason:Ns.CANCEL});break}},onBlur:d=>{o&&!d.currentTarget.contains(d.relatedTarget)&&kr(l,{reason:Ns.BLUR})}},n),className:sd({block:RH,modifiers:f.exports.useMemo(()=>({theme:i,itemTransition:s}),[i,s]),className:e}),style:{position:"absolute",...n==null?void 0:n.style},ref:t,children:r})},AH=()=>{let e,t=0;return{toggle:n=>{n?t++:t--,t=Math.max(t,0)},on:(n,r,o)=>{t?e||(e=setTimeout(()=>{e=0,r()},n)):o==null||o()},off:()=>{e&&(clearTimeout(e),e=0)}}},DH=(e,t)=>{const[n,r]=f.exports.useState(),i=f.exports.useRef({items:[],hoverIndex:-1,sorted:!1}).current,a=f.exports.useCallback((s,c)=>{const{items:u}=i;if(!s)i.items=[];else if(c)u.push(s);else{const d=u.indexOf(s);d>-1&&(u.splice(d,1),s.contains(document.activeElement)&&(t.current.focus(),r()))}i.hoverIndex=-1,i.sorted=!1},[i,t]),l=f.exports.useCallback((s,c,u)=>{const{items:d,hoverIndex:v}=i,h=()=>{if(i.sorted)return;const b=e.current.querySelectorAll(".szh-menu__item");d.sort((m,y)=>b1(b,m)-b1(b,y)),i.sorted=!0};let g=-1,p;switch(s){case rn.RESET:break;case rn.SET:p=c;break;case rn.UNSET:p=b=>b===c?void 0:b;break;case rn.FIRST:h(),g=0,p=d[g];break;case rn.LAST:h(),g=d.length-1,p=d[g];break;case rn.SET_INDEX:h(),g=u,p=d[g];break;case rn.INCREASE:h(),g=v,g<0&&(g=d.indexOf(c)),g++,g>=d.length&&(g=0),p=d[g];break;case rn.DECREASE:h(),g=v,g<0&&(g=d.indexOf(c)),g--,g<0&&(g=d.length-1),p=d[g];break}p||(g=-1),r(p),i.hoverIndex=g},[e,i]);return{hoverItem:n,dispatch:l,updateItems:a}},LH=(e,t,n,r)=>{const o=t.current.getBoundingClientRect(),i=e.current.getBoundingClientRect(),a=n===window?{left:0,top:0,right:document.documentElement.clientWidth,bottom:window.innerHeight}:n.getBoundingClientRect(),l=OH(r),s=g=>g+i.left-a.left-l.left,c=g=>g+i.left+o.width-a.right+l.right,u=g=>g+i.top-a.top-l.top,d=g=>g+i.top+o.height-a.bottom+l.bottom;return{menuRect:o,containerRect:i,getLeftOverflow:s,getRightOverflow:c,getTopOverflow:u,getBottomOverflow:d,confineHorizontally:g=>{let p=s(g);if(p<0)g-=p;else{const b=c(g);b>0&&(g-=b,p=s(g),p<0&&(g-=p))}return g},confineVertically:g=>{let p=u(g);if(p<0)g-=p;else{const b=d(g);b>0&&(g-=b,p=u(g),p<0&&(g-=p))}return g}}},zH=({arrowRef:e,menuY:t,anchorRect:n,containerRect:r,menuRect:o})=>{let i=n.top-r.top-t+n.height/2;const a=e.current.offsetHeight*1.25;return i=Math.max(a,i),i=Math.min(i,o.height-a),i},FH=({anchorRect:e,containerRect:t,menuRect:n,placeLeftorRightY:r,placeLeftX:o,placeRightX:i,getLeftOverflow:a,getRightOverflow:l,confineHorizontally:s,confineVertically:c,arrowRef:u,arrow:d,direction:v,position:h})=>{let g=v,p=r;h!=="initial"&&(p=c(p),h==="anchor"&&(p=Math.min(p,e.bottom-t.top),p=Math.max(p,e.top-t.top-n.height)));let b,m,y;return g==="left"?(b=o,h!=="initial"&&(m=a(b),m<0&&(y=l(i),(y<=0||-m>y)&&(b=i,g="right")))):(b=i,h!=="initial"&&(y=l(b),y>0&&(m=a(o),(m>=0||-m{let i=n.left-r.left-t+n.width/2;const a=e.current.offsetWidth*1.25;return i=Math.max(a,i),i=Math.min(i,o.width-a),i},BH=({anchorRect:e,containerRect:t,menuRect:n,placeToporBottomX:r,placeTopY:o,placeBottomY:i,getTopOverflow:a,getBottomOverflow:l,confineHorizontally:s,confineVertically:c,arrowRef:u,arrow:d,direction:v,position:h})=>{let g=v==="top"?"top":"bottom",p=r;h!=="initial"&&(p=s(p),h==="anchor"&&(p=Math.min(p,e.right-t.left),p=Math.max(p,e.left-t.left-n.width)));let b,m,y;return g==="top"?(b=o,h!=="initial"&&(m=a(b),m<0&&(y=l(i),(y<=0||-m>y)&&(b=i,g="bottom")))):(b=i,h!=="initial"&&(y=l(b),y>0&&(m=a(o),(m>=0||-m{const{menuRect:c,containerRect:u}=s,d=n==="left"||n==="right";let v=d?r:o,h=d?o:r;if(e){const $=l.current;d?v+=$.offsetWidth:h+=$.offsetHeight}const g=a.left-u.left-c.width-v,p=a.right-u.left+v,b=a.top-u.top-c.height-h,m=a.bottom-u.top+h;let y,S;t==="end"?(y=a.right-u.left-c.width,S=a.bottom-u.top-c.height):t==="center"?(y=a.left-u.left-(c.width-a.width)/2,S=a.top-u.top-(c.height-a.height)/2):(y=a.left-u.left,S=a.top-u.top),y+=v,S+=h;const x={...s,anchorRect:a,placeLeftX:g,placeRightX:p,placeLeftorRightY:S,placeTopY:b,placeBottomY:m,placeToporBottomX:y,arrowRef:l,arrow:e,direction:n,position:i};switch(n){case"left":case"right":return FH(x);case"top":case"bottom":default:return BH(x)}},fu=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u"?f.exports.useLayoutEffect:f.exports.useEffect;function w1(e,t){typeof e=="function"?e(t):e.current=t}const H$=(e,t)=>f.exports.useMemo(()=>e?t?n=>{w1(e,n),w1(t,n)}:e:t,[e,t]),$1=-9999,HH=({ariaLabel:e,menuClassName:t,menuStyle:n,arrow:r,arrowProps:o={},anchorPoint:i,anchorRef:a,containerRef:l,containerProps:s,focusProps:c,externalRef:u,parentScrollingRef:d,align:v="start",direction:h="bottom",position:g="auto",overflow:p="visible",setDownOverflow:b,repositionFlag:m,captureFocus:y=!0,state:S,endTransition:x,isDisabled:$,menuItemFocus:E,gap:w=0,shift:R=0,children:P,onClose:N,...I})=>{const[z,F]=f.exports.useState({x:$1,y:$1}),[T,D]=f.exports.useState({}),[_,O]=f.exports.useState(),[M,L]=f.exports.useState(h),[A]=f.exports.useState(AH),[B,k]=f.exports.useReducer(Ue=>Ue+1,1),{transition:j,boundingBoxRef:H,boundingBoxPadding:W,rootMenuRef:Y,rootAnchorRef:K,scrollNodesRef:q,reposition:ee,viewScroll:Z,submenuCloseDelay:Q}=f.exports.useContext(zm),{submenuCtx:ne,reposSubmenu:ae=m}=f.exports.useContext(S1),J=f.exports.useRef(null),re=f.exports.useRef(),fe=f.exports.useRef(),ve=f.exports.useRef(!1),pe=f.exports.useRef({width:0,height:0}),oe=f.exports.useRef(()=>{}),{hoverItem:se,dispatch:le,updateItems:Ce}=DH(J,re),ce=MH(S),de=_g(j,"open"),xe=_g(j,"close"),he=q.current,ke=Ue=>{switch(Ue.key){case co.HOME:le(rn.FIRST);break;case co.END:le(rn.LAST);break;case co.UP:le(rn.DECREASE,se);break;case co.DOWN:le(rn.INCREASE,se);break;case co.SPACE:Ue.target&&Ue.target.className.indexOf(du)!==-1&&Ue.preventDefault();return;default:return}Ue.preventDefault(),Ue.stopPropagation()},we=()=>{S==="closing"&&O(),kr(x)},ge=Ue=>{Ue.stopPropagation(),A.on(Q,()=>{le(rn.RESET),re.current.focus()})},Pe=Ue=>{Ue.target===Ue.currentTarget&&A.off()},Se=f.exports.useCallback(Ue=>{var He;const Xe=a?(He=a.current)==null?void 0:He.getBoundingClientRect():i?{left:i.x,right:i.x,top:i.y,bottom:i.y,width:0,height:0}:null;if(!Xe)return;he.menu||(he.menu=(H?H.current:Pv(Y.current))||window);const Le=LH(l,J,he.menu,W);let{arrowX:Re,arrowY:be,x:Ae,y:Me,computedDirection:$e}=jH({arrow:r,align:v,direction:h,gap:w,shift:R,position:g,anchorRect:Xe,arrowRef:fe,positionHelpers:Le});const{menuRect:Te}=Le;let ye=Te.height;if(!Ue&&p!=="visible"){const{getTopOverflow:Ge,getBottomOverflow:Ze}=Le;let et,ht;const mt=pe.current.height,ct=Ze(Me);if(ct>0||aa(ct,0)&&aa(ye,mt))et=ye-ct,ht=ct;else{const We=Ge(Me);(We<0||aa(We,0)&&aa(ye,mt))&&(et=ye+We,ht=0-We,et>=0&&(Me-=We))}et>=0?(ye=et,O({height:et,overflowAmt:ht})):O()}r&&D({x:Re,y:be}),F({x:Ae,y:Me}),L($e),pe.current={width:Te.width,height:ye}},[r,v,W,h,w,R,g,p,i,a,l,H,Y,he]);fu(()=>{ce&&(Se(),ve.current&&k()),ve.current=ce,oe.current=Se},[ce,Se,ae]),fu(()=>{_&&!b&&(J.current.scrollTop=0)},[_,b]),fu(()=>Ce,[Ce]),f.exports.useEffect(()=>{let{menu:Ue}=he;if(!ce||!Ue)return;if(Ue=Ue.addEventListener?Ue:window,!he.anchors){he.anchors=[];let Re=Pv(K&&K.current);for(;Re&&Re!==Ue;)he.anchors.push(Re),Re=Pv(Re)}let He=Z;if(he.anchors.length&&He==="initial"&&(He="auto"),He==="initial")return;const Xe=()=>{He==="auto"?y1(()=>Se(!0)):kr(N,{reason:Ns.SCROLL})},Le=he.anchors.concat(Z!=="initial"?Ue:[]);return Le.forEach(Re=>Re.addEventListener("scroll",Xe)),()=>Le.forEach(Re=>Re.removeEventListener("scroll",Xe))},[K,he,ce,N,Z,Se]);const st=!!_&&_.overflowAmt>0;f.exports.useEffect(()=>{if(st||!ce||!d)return;const Ue=()=>y1(Se),He=d.current;return He.addEventListener("scroll",Ue),()=>He.removeEventListener("scroll",Ue)},[ce,st,d,Se]),f.exports.useEffect(()=>{if(typeof ResizeObserver!="function"||ee==="initial")return;const Ue=new ResizeObserver(([Xe])=>{const{borderBoxSize:Le,target:Re}=Xe;let be,Ae;if(Le){const{inlineSize:Me,blockSize:$e}=Le[0]||Le;be=Me,Ae=$e}else{const Me=Re.getBoundingClientRect();be=Me.width,Ae=Me.height}be===0||Ae===0||aa(be,pe.current.width,1)&&aa(Ae,pe.current.height,1)||Gn.exports.flushSync(()=>{oe.current(),k()})}),He=J.current;return Ue.observe(He,{box:"border-box"}),()=>Ue.unobserve(He)},[ee]),f.exports.useEffect(()=>{if(!ce){le(rn.RESET),xe||O();return}const{position:Ue,alwaysUpdate:He}=E||{},Xe=()=>{Ue===C1.FIRST?le(rn.FIRST):Ue===C1.LAST?le(rn.LAST):Ue>=-1&&le(rn.SET_INDEX,void 0,Ue)};if(He)Xe();else if(y){const Le=setTimeout(()=>{const Re=J.current;Re&&!Re.contains(document.activeElement)&&(re.current.focus(),Xe())},de?170:100);return()=>clearTimeout(Le)}},[ce,de,xe,y,E,le]);const nt=f.exports.useMemo(()=>({isParentOpen:ce,submenuCtx:A,dispatch:le,updateItems:Ce}),[ce,A,le,Ce]);let Ne,Ee;_&&(b?Ee=_.overflowAmt:Ne=_.height);const _e=f.exports.useMemo(()=>({reposSubmenu:B,submenuCtx:A,overflow:p,overflowAmt:Ee,parentMenuRef:J,parentDir:M}),[B,A,p,Ee,M]),Be=Ne>=0?{maxHeight:Ne,overflow:p}:void 0,qe=f.exports.useMemo(()=>({state:S,dir:M}),[S,M]),it=f.exports.useMemo(()=>({dir:M}),[M]),ft=sd({block:du,element:IH,modifiers:it,className:o.className}),ut=ie("ul",{role:"menu","aria-label":e,...z$($),...Lm({onPointerEnter:ne==null?void 0:ne.off,onPointerMove:ge,onPointerLeave:Pe,onKeyDown:ke,onAnimationEnd:we},I),ref:H$(u,J),className:sd({block:du,modifiers:qe,className:t}),style:{...n,...Be,margin:0,display:S==="closed"?"none":void 0,position:Tv,left:z.x,top:z.y},children:[C("li",{tabIndex:-1,style:{position:Tv,left:0,top:0,display:"block",outline:"none"},ref:re,...x1,...c}),r&&C("li",{...x1,...o,className:ft,style:{display:"block",position:Tv,left:T.x,top:T.y,...o.style},ref:fe}),C(S1.Provider,{value:_e,children:C(k$.Provider,{value:nt,children:C(F$.Provider,{value:se,children:kr(P,qe)})})})]});return s?C(_H,{...s,isOpen:ce,children:ut}):ut},W$=f.exports.forwardRef(function({"aria-label":t,className:n,containerProps:r,initialMounted:o,unmountOnClose:i,transition:a,transitionTimeout:l,boundingBoxRef:s,boundingBoxPadding:c,reposition:u="auto",submenuOpenDelay:d=300,submenuCloseDelay:v=150,viewScroll:h="initial",portal:g,theming:p,onItemClick:b,...m},y){const S=f.exports.useRef(null),x=f.exports.useRef({}),{anchorRef:$,state:E,onClose:w}=m,R=f.exports.useMemo(()=>({initialMounted:o,unmountOnClose:i,transition:a,transitionTimeout:l,boundingBoxRef:s,boundingBoxPadding:c,rootMenuRef:S,rootAnchorRef:$,scrollNodesRef:x,reposition:u,viewScroll:h,submenuOpenDelay:d,submenuCloseDelay:v}),[o,i,a,l,$,s,c,u,h,d,v]),P=f.exports.useMemo(()=>({handleClick(I,z){I.stopPropagation||kr(b,I);let F=I.keepOpen;F===void 0&&(F=z&&I.key===co.SPACE),F||kr(w,{value:I.value,key:I.key,reason:Ns.CLICK})},handleClose(I){kr(w,{key:I,reason:Ns.CLICK})}}),[b,w]);if(!E)return null;const N=C(zm.Provider,{value:R,children:C(B$.Provider,{value:P,children:C(HH,{...m,ariaLabel:t||"Menu",externalRef:y,containerRef:S,containerProps:{className:n,containerRef:S,containerProps:r,theming:p,transition:a,onClose:w}})})});return g===!0&&typeof document<"u"?Gn.exports.createPortal(N,document.body):g?g.target?Gn.exports.createPortal(N,g.target):g.stablePosition?null:N:N}),WH=(e,t)=>{const n=f.exports.memo(t),r=f.exports.forwardRef((o,i)=>{const a=f.exports.useRef(null);return C(n,{...o,itemRef:a,externalRef:i,isHovering:f.exports.useContext(F$)===a.current})});return r.displayName=`WithHovering(${e})`,r},VH=(e,t,n)=>{fu(()=>{if(e)return;const r=t.current;return n(r,!0),()=>{n(r)}},[e,t,n])},UH=(e,t,n,r)=>{const{submenuCloseDelay:o}=f.exports.useContext(zm),{isParentOpen:i,submenuCtx:a,dispatch:l,updateItems:s}=f.exports.useContext(k$),c=()=>{!n&&!r&&l(rn.SET,e.current)},u=()=>{!r&&l(rn.UNSET,e.current)},d=g=>{n&&!g.currentTarget.contains(g.relatedTarget)&&u()},v=g=>{r||(g.stopPropagation(),a.on(o,c,c))},h=(g,p)=>{a.off(),!p&&u()};return VH(r,e,s),f.exports.useEffect(()=>{n&&i&&t.current&&t.current.focus()},[t,n,i]),{setHover:c,onBlur:d,onPointerMove:v,onPointerLeave:h}},cd=WH("MenuItem",function({className:t,value:n,href:r,type:o,checked:i,disabled:a,children:l,onClick:s,isHovering:c,itemRef:u,externalRef:d,...v}){const h=!!a,{setHover:g,...p}=UH(u,u,c,h),b=f.exports.useContext(B$),m=f.exports.useContext(TH),y=o==="radio",S=o==="checkbox",x=!!r&&!h&&!y&&!S,$=y?m.value===n:S?!!i:!1,E=I=>{if(h){I.stopPropagation(),I.preventDefault();return}const z={value:n,syntheticEvent:I};I.key!==void 0&&(z.key=I.key),S&&(z.checked=!$),y&&(z.name=m.name),kr(s,z),y&&kr(m.onRadioChange,z),b.handleClick(z,S||y)},w=I=>{if(!!c)switch(I.key){case co.ENTER:I.preventDefault();case co.SPACE:x?u.current.click():E(I)}},R=f.exports.useMemo(()=>({type:o,disabled:h,hover:c,checked:$,anchor:x}),[o,h,c,$,x]),P=Lm({...p,onPointerDown:g,onKeyDown:w,onClick:E},v),N={role:y?"menuitemradio":S?"menuitemcheckbox":j$,"aria-checked":y||S?$:void 0,...z$(h,c),...P,ref:H$(d,u),className:sd({block:du,element:PH,modifiers:R,className:t}),children:f.exports.useMemo(()=>kr(l,R),[l,R])};return x?C("li",{role:NH,children:C("a",{href:r,...N})}):C("li",{...N})});var V$={exports:{}};/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(e,t){(function(r,o){e.exports=o()})(Hr,function(){return function(){var n={686:function(i,a,l){l.d(a,{default:function(){return B}});var s=l(279),c=l.n(s),u=l(370),d=l.n(u),v=l(817),h=l.n(v);function g(k){try{return document.execCommand(k)}catch{return!1}}var p=function(j){var H=h()(j);return g("cut"),H},b=p;function m(k){var j=document.documentElement.getAttribute("dir")==="rtl",H=document.createElement("textarea");H.style.fontSize="12pt",H.style.border="0",H.style.padding="0",H.style.margin="0",H.style.position="absolute",H.style[j?"right":"left"]="-9999px";var W=window.pageYOffset||document.documentElement.scrollTop;return H.style.top="".concat(W,"px"),H.setAttribute("readonly",""),H.value=k,H}var y=function(j,H){var W=m(j);H.container.appendChild(W);var Y=h()(W);return g("copy"),W.remove(),Y},S=function(j){var H=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},W="";return typeof j=="string"?W=y(j,H):j instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(j==null?void 0:j.type)?W=y(j.value,H):(W=h()(j),g("copy")),W},x=S;function $(k){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$=function(H){return typeof H}:$=function(H){return H&&typeof Symbol=="function"&&H.constructor===Symbol&&H!==Symbol.prototype?"symbol":typeof H},$(k)}var E=function(){var j=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},H=j.action,W=H===void 0?"copy":H,Y=j.container,K=j.target,q=j.text;if(W!=="copy"&&W!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(K!==void 0)if(K&&$(K)==="object"&&K.nodeType===1){if(W==="copy"&&K.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(W==="cut"&&(K.hasAttribute("readonly")||K.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(q)return x(q,{container:Y});if(K)return W==="cut"?b(K):x(K,{container:Y})},w=E;function R(k){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(H){return typeof H}:R=function(H){return H&&typeof Symbol=="function"&&H.constructor===Symbol&&H!==Symbol.prototype?"symbol":typeof H},R(k)}function P(k,j){if(!(k instanceof j))throw new TypeError("Cannot call a class as a function")}function N(k,j){for(var H=0;H"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch{return!1}}function M(k){return M=Object.setPrototypeOf?Object.getPrototypeOf:function(H){return H.__proto__||Object.getPrototypeOf(H)},M(k)}function L(k,j){var H="data-clipboard-".concat(k);if(!!j.hasAttribute(H))return j.getAttribute(H)}var A=function(k){z(H,k);var j=T(H);function H(W,Y){var K;return P(this,H),K=j.call(this),K.resolveOptions(Y),K.listenClick(W),K}return I(H,[{key:"resolveOptions",value:function(){var Y=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof Y.action=="function"?Y.action:this.defaultAction,this.target=typeof Y.target=="function"?Y.target:this.defaultTarget,this.text=typeof Y.text=="function"?Y.text:this.defaultText,this.container=R(Y.container)==="object"?Y.container:document.body}},{key:"listenClick",value:function(Y){var K=this;this.listener=d()(Y,"click",function(q){return K.onClick(q)})}},{key:"onClick",value:function(Y){var K=Y.delegateTarget||Y.currentTarget,q=this.action(K)||"copy",ee=w({action:q,container:this.container,target:this.target(K),text:this.text(K)});this.emit(ee?"success":"error",{action:q,text:ee,trigger:K,clearSelection:function(){K&&K.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(Y){return L("action",Y)}},{key:"defaultTarget",value:function(Y){var K=L("target",Y);if(K)return document.querySelector(K)}},{key:"defaultText",value:function(Y){return L("text",Y)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(Y){var K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return x(Y,K)}},{key:"cut",value:function(Y){return b(Y)}},{key:"isSupported",value:function(){var Y=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],K=typeof Y=="string"?[Y]:Y,q=!!document.queryCommandSupported;return K.forEach(function(ee){q=q&&!!document.queryCommandSupported(ee)}),q}}]),H}(c()),B=A},828:function(i){var a=9;if(typeof Element<"u"&&!Element.prototype.matches){var l=Element.prototype;l.matches=l.matchesSelector||l.mozMatchesSelector||l.msMatchesSelector||l.oMatchesSelector||l.webkitMatchesSelector}function s(c,u){for(;c&&c.nodeType!==a;){if(typeof c.matches=="function"&&c.matches(u))return c;c=c.parentNode}}i.exports=s},438:function(i,a,l){var s=l(828);function c(v,h,g,p,b){var m=d.apply(this,arguments);return v.addEventListener(g,m,b),{destroy:function(){v.removeEventListener(g,m,b)}}}function u(v,h,g,p,b){return typeof v.addEventListener=="function"?c.apply(null,arguments):typeof g=="function"?c.bind(null,document).apply(null,arguments):(typeof v=="string"&&(v=document.querySelectorAll(v)),Array.prototype.map.call(v,function(m){return c(m,h,g,p,b)}))}function d(v,h,g,p){return function(b){b.delegateTarget=s(b.target,h),b.delegateTarget&&p.call(v,b)}}i.exports=u},879:function(i,a){a.node=function(l){return l!==void 0&&l instanceof HTMLElement&&l.nodeType===1},a.nodeList=function(l){var s=Object.prototype.toString.call(l);return l!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in l&&(l.length===0||a.node(l[0]))},a.string=function(l){return typeof l=="string"||l instanceof String},a.fn=function(l){var s=Object.prototype.toString.call(l);return s==="[object Function]"}},370:function(i,a,l){var s=l(879),c=l(438);function u(g,p,b){if(!g&&!p&&!b)throw new Error("Missing required arguments");if(!s.string(p))throw new TypeError("Second argument must be a String");if(!s.fn(b))throw new TypeError("Third argument must be a Function");if(s.node(g))return d(g,p,b);if(s.nodeList(g))return v(g,p,b);if(s.string(g))return h(g,p,b);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function d(g,p,b){return g.addEventListener(p,b),{destroy:function(){g.removeEventListener(p,b)}}}function v(g,p,b){return Array.prototype.forEach.call(g,function(m){m.addEventListener(p,b)}),{destroy:function(){Array.prototype.forEach.call(g,function(m){m.removeEventListener(p,b)})}}}function h(g,p,b){return c(document.body,g,p,b)}i.exports=u},817:function(i){function a(l){var s;if(l.nodeName==="SELECT")l.focus(),s=l.value;else if(l.nodeName==="INPUT"||l.nodeName==="TEXTAREA"){var c=l.hasAttribute("readonly");c||l.setAttribute("readonly",""),l.select(),l.setSelectionRange(0,l.value.length),c||l.removeAttribute("readonly"),s=l.value}else{l.hasAttribute("contenteditable")&&l.focus();var u=window.getSelection(),d=document.createRange();d.selectNodeContents(l),u.removeAllRanges(),u.addRange(d),s=u.toString()}return s}i.exports=a},279:function(i){function a(){}a.prototype={on:function(l,s,c){var u=this.e||(this.e={});return(u[l]||(u[l]=[])).push({fn:s,ctx:c}),this},once:function(l,s,c){var u=this;function d(){u.off(l,d),s.apply(c,arguments)}return d._=s,this.on(l,d,c)},emit:function(l){var s=[].slice.call(arguments,1),c=((this.e||(this.e={}))[l]||[]).slice(),u=0,d=c.length;for(u;u{const l=new YH(".CardMessageLink-Copy");return()=>{l.destroy()}},[]);const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState({x:0,y:0}),i=l=>{typeof document.hasFocus=="function"&&!document.hasFocus()||(l.preventDefault(),o({x:l.clientX,y:l.clientY}),n(!0))},a=()=>{i9(e.info.Url)};return ie("div",{className:"CardMessage CardMessageLink",size:"small",onDoubleClick:a,onContextMenu:i,children:[C("div",{className:"CardMessage-Title",children:e.info.Title}),ie("div",{className:"CardMessage-Content",children:[C("div",{className:"CardMessage-Desc",children:e.info.Description}),C(cu,{className:"CardMessageLink-Image",src:e.image,height:45,width:45,preview:!1,fallback:C9})]}),C("div",{className:e.info.DisPlayName===""?"CardMessageLink-Line-None":"CardMessageLink-Line"}),C("div",{className:"CardMessageLink-Name",children:e.info.DisPlayName}),ie(W$,{anchorPoint:r,state:t?"open":"closed",direction:"right",onClose:()=>n(!1),menuClassName:"CardMessage-Menu",children:[C(cd,{onClick:a,children:"\u6253\u5F00"}),C(cd,{className:"CardMessageLink-Copy",onClick:()=>handleOpenFile("fiexplorerle"),"data-clipboard-text":e.info.Url,children:"\u590D\u5236\u94FE\u63A5"})]})]})}function qH(e){const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState(!1),[i,a]=f.exports.useState({x:0,y:0}),l=u=>{typeof document.hasFocus=="function"&&!document.hasFocus()||(u.preventDefault(),a({x:u.clientX,y:u.clientY}),o(!0))},s=u=>{JB(e.info.filePath,u==="explorer").then(d=>{JSON.parse(d).status==="failed"&&n(!0)})},c=({hover:u})=>u?"CardMessage-Menu-hover":"CardMessage-Menu";return ie("div",{className:"CardMessage CardMessageFile",size:"small",onDoubleClick:()=>s("file"),onContextMenu:l,children:[C("div",{className:"CardMessage-Title",children:e.info.fileName}),ie("div",{className:"CardMessage-Content",children:[ie("div",{className:"CardMessage-Desc",children:[e.info.fileSize,C("span",{className:"CardMessage-Desc-Span",children:t?"\u6587\u4EF6\u4E0D\u5B58\u5728":""})]}),C("div",{className:"CardMessageFile-Icon",children:C(cx,{})})]}),ie(W$,{anchorPoint:i,state:r?"open":"closed",direction:"right",onClose:()=>o(!1),menuClassName:"CardMessage-Menu",children:[C(cd,{className:c,onClick:()=>s("file"),children:"\u6253\u5F00"}),C(cd,{className:c,onClick:()=>s("fiexplorerle"),children:"\u5728\u6587\u4EF6\u5939\u4E2D\u663E\u793A"})]})]})}function XH(e){let t=null,n=null;switch(e.info.Type){case Fm:switch(e.info.SubType){case Q$:n=C(cx,{});break;case X$:n=C(mP,{});break}case U$:t=ie("div",{className:"MessageRefer-Content-Text",children:[e.info.Displayname,":",n,e.info.Content]});break;case q$:t=C(v4,{});break;case Y$:t=C(LP,{});break;case K$:t=C(S4,{});break;case G$:t=C(RI,{});break;default:t=ie("div",{children:["\u672A\u77E5\u7684\u5F15\u7528\u7C7B\u578B ID:",e.info.Svrid,"Type:",e.info.Type]})}return ie("div",{className:e.position==="left"?"MessageRefer-Left":"MessageRefer-Right",children:[C(Dm,{className:"MessageRefer-MessageText",text:e.content}),C("div",{className:"MessageRefer-Content",children:t})]})}function J$(e){switch(e.content.type){case U$:return C(Dm,{text:e.content.content});case Y$:return C(cu,{src:e.content.ThumbPath,preview:{src:e.content.ImagePath}});case K$:return C(cu,{src:e.content.ThumbPath,preview:{imageRender:(t,n)=>C("video",{className:"video_view",height:"100%",width:"100%",controls:!0,src:e.content.VideoPath}),onVisibleChange:(t,n,r)=>{t===!1&&n===!0&&document.getElementsByClassName("video_view")[0].pause()}}});case G$:return C(m$,{className:"CardMessageText",children:C("audio",{className:"CardMessageAudio",controls:!0,src:e.content.VoicePath})});case q$:return C(cu,{src:e.content.EmojiPath,height:"110px",width:"110px",preview:!1,fallback:x9});case GH:return C("div",{className:"System-Text",children:e.content.content});case Fm:switch(e.content.SubType){case X$:return C(KH,{info:e.content.LinkInfo,image:e.content.ThumbPath,tmp:e.content.MsgSvrId});case Z$:return C(XH,{content:e.content.content,info:e.content.ReferInfo,position:e.content.IsSender?"right":"left"});case Q$:return C(qH,{info:e.content.fileInfo})}default:return ie("div",{children:["ID: ",e.content.LocalId,"\u672A\u77E5\u7C7B\u578B: ",e.content.type," \u5B50\u7C7B\u578B: ",e.content.SubType]})}}function QH(e){let t=J$(e);return e.content.type==Fm&&e.content.SubType==Z$&&(t=C(Dm,{text:e.content.content})),t}function ZH(e){return C(Tt,{children:e.selectTag===""?C(_d,{}):ie("div",{className:"SearchInputIcon",children:[C($I,{className:"SearchInputIcon-size SearchInputIcon-first"}),C("div",{className:"SearchInputIcon-size SearchInputIcon-second",children:e.selectTag}),C(eo,{className:"SearchInputIcon-size SearchInputIcon-third",onClick:()=>e.onClickClose()})]})})}function eE(e){const t=r=>{e.onChange&&e.onChange(r.target.value)},n=r=>{r.stopPropagation()};return C("div",{className:"wechat-SearchInput",children:C(ai,{theme:{components:{Input:{activeBorderColor:"#E3E4E5",activeShadow:"#E3E4E5",hoverBorderColor:"#E3E4E5"}}},children:C(C$,{className:"wechat-SearchInput-Input",placeholder:e.selectTag===""?"\u641C\u7D22":"",prefix:C(ZH,{selectTag:e.selectTag,onClickClose:()=>e.onClickClose()}),allowClear:!0,onChange:t,onClick:n})})})}function JH(e){const t=f.exports.useMemo(()=>e.renderMessageContent(e.message),[e.message]);return ie("div",{className:"MessageBubble RecordsUi-MessageBubble",onDoubleClick:()=>{e.onDoubleClick&&e.onDoubleClick(e.message)},children:[C("time",{className:"Time",dateTime:Lt(e.message.createdAt).format(),children:Lt(e.message.createdAt*1e3).format("YYYY\u5E74M\u6708D\u65E5 HH:mm")}),ie("div",{className:"MessageBubble-content-left",children:[C("div",{className:"MessageBubble-content-Avatar",children:C(Yo,{className:"MessageBubble-Avatar-left",src:e.message.user.avatar,size:{xs:40,sm:40,md:40,lg:40,xl:40,xxl:40},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"})}),ie("div",{className:"Bubble-left",children:[C("div",{className:"MessageBubble-Name-left",truncate:1,children:e.message.user.name}),t]})]})]})}function eW(e){const t=f.exports.useRef(0),n=f.exports.useRef(null),r=i=>{i.srcElement.scrollTop===0?(t.current=i.srcElement.scrollHeight,n.current=i.srcElement,e.atBottom&&e.atBottom()):(t.current=0,n.current=null)};function o(){e.next()}return f.exports.useEffect(()=>{t.current!==0&&n.current&&(n.current.scrollTop=-(n.current.scrollHeight-t.current),t.current=0,n.current=null)},[e.messages]),C("div",{id:"RecordsUiscrollableDiv",children:C(D$,{scrollableTarget:"RecordsUiscrollableDiv",dataLength:e.messages.length,next:o,hasMore:e.hasMore,inverse:!0,onScroll:r,children:e.messages.map(i=>C(JH,{message:i,renderMessageContent:e.renderMessageContent,onDoubleClick:e.onDoubleClick},i.key))})})}function tW(e){return C("div",{className:"RecordsUi",children:C(eW,{messages:e.messages,next:e.fetchMoreData,hasMore:e.hasMore,renderMessageContent:e.renderMessageContent,atBottom:e.atBottom,onDoubleClick:e.onDoubleClick})})}var nW={locale:"zh_CN",yearFormat:"YYYY\u5E74",cellDateFormat:"D",cellMeridiemFormat:"A",today:"\u4ECA\u5929",now:"\u6B64\u523B",backToToday:"\u8FD4\u56DE\u4ECA\u5929",ok:"\u786E\u5B9A",timeSelect:"\u9009\u62E9\u65F6\u95F4",dateSelect:"\u9009\u62E9\u65E5\u671F",weekSelect:"\u9009\u62E9\u5468",clear:"\u6E05\u9664",month:"\u6708",year:"\u5E74",previousMonth:"\u4E0A\u4E2A\u6708 (\u7FFB\u9875\u4E0A\u952E)",nextMonth:"\u4E0B\u4E2A\u6708 (\u7FFB\u9875\u4E0B\u952E)",monthSelect:"\u9009\u62E9\u6708\u4EFD",yearSelect:"\u9009\u62E9\u5E74\u4EFD",decadeSelect:"\u9009\u62E9\u5E74\u4EE3",previousYear:"\u4E0A\u4E00\u5E74 (Control\u952E\u52A0\u5DE6\u65B9\u5411\u952E)",nextYear:"\u4E0B\u4E00\u5E74 (Control\u952E\u52A0\u53F3\u65B9\u5411\u952E)",previousDecade:"\u4E0A\u4E00\u5E74\u4EE3",nextDecade:"\u4E0B\u4E00\u5E74\u4EE3",previousCentury:"\u4E0A\u4E00\u4E16\u7EAA",nextCentury:"\u4E0B\u4E00\u4E16\u7EAA"};const rW={placeholder:"\u8BF7\u9009\u62E9\u65F6\u95F4",rangePlaceholder:["\u5F00\u59CB\u65F6\u95F4","\u7ED3\u675F\u65F6\u95F4"]},oW=rW,tE={lang:Object.assign({placeholder:"\u8BF7\u9009\u62E9\u65E5\u671F",yearPlaceholder:"\u8BF7\u9009\u62E9\u5E74\u4EFD",quarterPlaceholder:"\u8BF7\u9009\u62E9\u5B63\u5EA6",monthPlaceholder:"\u8BF7\u9009\u62E9\u6708\u4EFD",weekPlaceholder:"\u8BF7\u9009\u62E9\u5468",rangePlaceholder:["\u5F00\u59CB\u65E5\u671F","\u7ED3\u675F\u65E5\u671F"],rangeYearPlaceholder:["\u5F00\u59CB\u5E74\u4EFD","\u7ED3\u675F\u5E74\u4EFD"],rangeMonthPlaceholder:["\u5F00\u59CB\u6708\u4EFD","\u7ED3\u675F\u6708\u4EFD"],rangeQuarterPlaceholder:["\u5F00\u59CB\u5B63\u5EA6","\u7ED3\u675F\u5B63\u5EA6"],rangeWeekPlaceholder:["\u5F00\u59CB\u5468","\u7ED3\u675F\u5468"]},nW),timePickerLocale:Object.assign({},oW)};tE.lang.ok="\u786E\u5B9A";const iW=tE;var aW={exports:{}};(function(e,t){(function(n,r){e.exports=r($m.exports)})(Hr,function(n){function r(a){return a&&typeof a=="object"&&"default"in a?a:{default:a}}var o=r(n),i={name:"zh-cn",weekdays:"\u661F\u671F\u65E5_\u661F\u671F\u4E00_\u661F\u671F\u4E8C_\u661F\u671F\u4E09_\u661F\u671F\u56DB_\u661F\u671F\u4E94_\u661F\u671F\u516D".split("_"),weekdaysShort:"\u5468\u65E5_\u5468\u4E00_\u5468\u4E8C_\u5468\u4E09_\u5468\u56DB_\u5468\u4E94_\u5468\u516D".split("_"),weekdaysMin:"\u65E5_\u4E00_\u4E8C_\u4E09_\u56DB_\u4E94_\u516D".split("_"),months:"\u4E00\u6708_\u4E8C\u6708_\u4E09\u6708_\u56DB\u6708_\u4E94\u6708_\u516D\u6708_\u4E03\u6708_\u516B\u6708_\u4E5D\u6708_\u5341\u6708_\u5341\u4E00\u6708_\u5341\u4E8C\u6708".split("_"),monthsShort:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),ordinal:function(a,l){return l==="W"?a+"\u5468":a+"\u65E5"},weekStart:1,yearStart:4,formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY\u5E74M\u6708D\u65E5",LLL:"YYYY\u5E74M\u6708D\u65E5Ah\u70B9mm\u5206",LLLL:"YYYY\u5E74M\u6708D\u65E5ddddAh\u70B9mm\u5206",l:"YYYY/M/D",ll:"YYYY\u5E74M\u6708D\u65E5",lll:"YYYY\u5E74M\u6708D\u65E5 HH:mm",llll:"YYYY\u5E74M\u6708D\u65E5dddd HH:mm"},relativeTime:{future:"%s\u5185",past:"%s\u524D",s:"\u51E0\u79D2",m:"1 \u5206\u949F",mm:"%d \u5206\u949F",h:"1 \u5C0F\u65F6",hh:"%d \u5C0F\u65F6",d:"1 \u5929",dd:"%d \u5929",M:"1 \u4E2A\u6708",MM:"%d \u4E2A\u6708",y:"1 \u5E74",yy:"%d \u5E74"},meridiem:function(a,l){var s=100*a+l;return s<600?"\u51CC\u6668":s<900?"\u65E9\u4E0A":s<1100?"\u4E0A\u5348":s<1300?"\u4E2D\u5348":s<1800?"\u4E0B\u5348":"\u665A\u4E0A"}};return o.default.locale(i,null,!0),i})})(aW);var nE={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n="minute",r=/[+-]\d\d(?::?\d\d)?/g,o=/([+-]|\d\d)/g;return function(i,a,l){var s=a.prototype;l.utc=function(p){var b={date:p,utc:!0,args:arguments};return new a(b)},s.utc=function(p){var b=l(this.toDate(),{locale:this.$L,utc:!0});return p?b.add(this.utcOffset(),n):b},s.local=function(){return l(this.toDate(),{locale:this.$L,utc:!1})};var c=s.parse;s.parse=function(p){p.utc&&(this.$u=!0),this.$utils().u(p.$offset)||(this.$offset=p.$offset),c.call(this,p)};var u=s.init;s.init=function(){if(this.$u){var p=this.$d;this.$y=p.getUTCFullYear(),this.$M=p.getUTCMonth(),this.$D=p.getUTCDate(),this.$W=p.getUTCDay(),this.$H=p.getUTCHours(),this.$m=p.getUTCMinutes(),this.$s=p.getUTCSeconds(),this.$ms=p.getUTCMilliseconds()}else u.call(this)};var d=s.utcOffset;s.utcOffset=function(p,b){var m=this.$utils().u;if(m(p))return this.$u?0:m(this.$offset)?d.call(this):this.$offset;if(typeof p=="string"&&(p=function($){$===void 0&&($="");var E=$.match(r);if(!E)return null;var w=(""+E[0]).match(o)||["-",0,0],R=w[0],P=60*+w[1]+ +w[2];return P===0?0:R==="+"?P:-P}(p),p===null))return this;var y=Math.abs(p)<=16?60*p:p,S=this;if(b)return S.$offset=y,S.$u=p===0,S;if(p!==0){var x=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(S=this.local().add(y+x,n)).$offset=y,S.$x.$localOffset=x}else S=this.utc();return S};var v=s.format;s.format=function(p){var b=p||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return v.call(this,b)},s.valueOf=function(){var p=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*p},s.isUTC=function(){return!!this.$u},s.toISOString=function(){return this.toDate().toISOString()},s.toString=function(){return this.toDate().toUTCString()};var h=s.toDate;s.toDate=function(p){return p==="s"&&this.$offset?l(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():h.call(this)};var g=s.diff;s.diff=function(p,b,m){if(p&&this.$u===p.$u)return g.call(this,p,b,m);var y=this.local(),S=l(p).local();return g.call(y,S,b,m)}}})})(nE);const lW=nE.exports;var rE={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n={year:0,month:1,day:2,hour:3,minute:4,second:5},r={};return function(o,i,a){var l,s=function(v,h,g){g===void 0&&(g={});var p=new Date(v),b=function(m,y){y===void 0&&(y={});var S=y.timeZoneName||"short",x=m+"|"+S,$=r[x];return $||($=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:m,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:S}),r[x]=$),$}(h,g);return b.formatToParts(p)},c=function(v,h){for(var g=s(v,h),p=[],b=0;b=0&&(p[x]=parseInt(S,10))}var $=p[3],E=$===24?0:$,w=p[0]+"-"+p[1]+"-"+p[2]+" "+E+":"+p[4]+":"+p[5]+":000",R=+v;return(a.utc(w).valueOf()-(R-=R%1e3))/6e4},u=i.prototype;u.tz=function(v,h){v===void 0&&(v=l);var g=this.utcOffset(),p=this.toDate(),b=p.toLocaleString("en-US",{timeZone:v}),m=Math.round((p-new Date(b))/1e3/60),y=a(b,{locale:this.$L}).$set("millisecond",this.$ms).utcOffset(15*-Math.round(p.getTimezoneOffset()/15)-m,!0);if(h){var S=y.utcOffset();y=y.add(g-S,"minute")}return y.$x.$timezone=v,y},u.offsetName=function(v){var h=this.$x.$timezone||a.tz.guess(),g=s(this.valueOf(),h,{timeZoneName:v}).find(function(p){return p.type.toLowerCase()==="timezonename"});return g&&g.value};var d=u.startOf;u.startOf=function(v,h){if(!this.$x||!this.$x.$timezone)return d.call(this,v,h);var g=a(this.format("YYYY-MM-DD HH:mm:ss:SSS"),{locale:this.$L});return d.call(g,v,h).tz(this.$x.$timezone,!0)},a.tz=function(v,h,g){var p=g&&h,b=g||h||l,m=c(+a(),b);if(typeof v!="string")return a(v).tz(b);var y=function(E,w,R){var P=E-60*w*1e3,N=c(P,R);if(w===N)return[P,w];var I=c(P-=60*(N-w)*1e3,R);return N===I?[P,N]:[E-60*Math.min(N,I)*1e3,Math.max(N,I)]}(a.utc(v,p).valueOf(),m,b),S=y[0],x=y[1],$=a(S).utcOffset(x);return $.$x.$timezone=b,$},a.tz.guess=function(){return Intl.DateTimeFormat().resolvedOptions().timeZone},a.tz.setDefault=function(v){l=v}}})})(rE);const sW=rE.exports,cW=()=>C("div",{className:"CalendarLoading",children:C(oB,{tip:"\u52A0\u8F7D\u4E2D...",size:"large",children:C("div",{className:"content"})})}),uW=({info:e,selectDate:t})=>{const[n,r]=f.exports.useState([]),[o,i]=f.exports.useState(!0),a=f.exports.useRef(null);f.exports.useEffect(()=>{Lt.extend(lW),Lt.extend(sW),Lt.tz.setDefault()},[]),f.exports.useEffect(()=>{XB(e.UserName).then(c=>{r(JSON.parse(c).Date),i(!1)})},[e.UserName]);const l=c=>{for(let u=0;u{u.source==="date"&&(a.current=c,t&&t(c.valueOf()/1e3))};return C(Tt,{children:o?C(cW,{}):C(cF,{className:"CalendarChoose",disabledDate:l,fullscreen:!1,locale:iW,validRange:n.length>0?[Lt(n[n.length-1]),Lt(n[0])]:void 0,defaultValue:a.current?a.current:n.length>0?Lt(n[0]):void 0,onSelect:s})})};const dW=["\u6587\u4EF6","\u56FE\u7247\u4E0E\u89C6\u9891","\u94FE\u63A5","\u65E5\u671F"],fW=["\u6587\u4EF6","\u56FE\u7247\u4E0E\u89C6\u9891","\u94FE\u63A5","\u65E5\u671F","\u7FA4\u6210\u5458"];function vW(e){const[t,n]=f.exports.useState(!1),r=()=>{e.info.UserName&&n(!0)},o=()=>{n(!1)},{messages:i,prependMsgs:a,appendMsgs:l,setMsgs:s}=L$([]),[c,u]=f.exports.useState(!1),[d,v]=f.exports.useState(!0),[h,g]=f.exports.useState(""),[p,b]=f.exports.useState(""),[m,y]=f.exports.useState(1),[S,x]=f.exports.useState(!1),[$,E]=f.exports.useState(e.info.Time),[w,R]=f.exports.useState(!1),[P,N]=f.exports.useState("");f.exports.useEffect(()=>{e.info.UserName&&$>0&&p!="\u65E5\u671F"&&(u(!0),QB(e.info.UserName,$,h,p,30).then(A=>{let B=JSON.parse(A);B.Total==0&&(v(!1),i.length==0&&R(!0));let k=[];B.Rows.forEach(j=>{k.unshift({_id:j.MsgSvrId,content:j,position:j.type===1e4?"middle":j.IsSender===1?"right":"left",user:{avatar:j.userInfo.SmallHeadImgUrl,name:j.userInfo.ReMark===""?j.userInfo.NickName:j.userInfo.ReMark},createdAt:j.createTime,key:j.MsgSvrId})}),u(!1),a(k)}))},[e.info.UserName,$,h,p]);const I=()=>{Ts("fetchMoreData"),c||setTimeout(()=>{E(i[0].createdAt-1)},300)},z=A=>{console.log("onKeyWordChange",A),E(e.info.Time),s([]),y(m+1),g(A),R(!1)},F=f.exports.useCallback(oE(A=>{z(A)},600),[]),T=A=>{console.log("onFilterTag",A),A!=="\u7FA4\u6210\u5458"&&(s([]),y(m+1),E(e.info.Time),b(A),R(!1),x(A==="\u65E5\u671F"),N(""))},D=()=>{s([]),y(m+1),E(e.info.Time),b(""),R(!1),N("")},_=e.info.IsGroup?fW:dW,O=A=>{o(),e.onSelectMessage&&e.onSelectMessage(A)},M=A=>{o(),e.onSelectDate&&e.onSelectDate(A)},L=A=>{console.log(A),b("\u7FA4\u6210\u5458"+A.UserName),N(A.NickName),E(e.info.Time),s([]),y(m+1),g(""),R(!1),x(!1)};return ie("div",{children:[C("div",{onClick:r,children:e.children}),C(js,{className:"ChattingRecords-Modal",overlayClassName:"ChattingRecords-Modal-Overlay",isOpen:t,onRequestClose:o,children:ie("div",{className:"ChattingRecords-Modal-Body",children:[ie("div",{className:"ChattingRecords-Modal-Bar",children:[ie("div",{className:"ChattingRecords-Modal-Bar-Top",children:[C("div",{children:e.info.NickName}),C("div",{className:"ChattingRecords-Modal-Bar-button",title:"\u5173\u95ED",onClick:o,children:C(eo,{className:"ChattingRecords-Modal-Bar-button-icon"})})]}),C(eE,{onChange:F,selectTag:p.includes("\u7FA4\u6210\u5458")?"\u7FA4\u6210\u5458":p,onClickClose:D}),C("div",{className:"ChattingRecords-Modal-Bar-Tag",children:_.map(A=>C("div",{onClick:()=>T(A),children:A==="\u7FA4\u6210\u5458"?C(gW,{info:e.info,onClick:L,children:A}):A},Am()))})]}),S==!1?w?C(pW,{text:h!==""?h:P}):C(tW,{messages:i,fetchMoreData:I,hasMore:d&&!c,renderMessageContent:QH,onDoubleClick:O},m):C(uW,{info:e.info,selectDate:M})]})})]})}function oE(e,t){let n;return function(...r){n&&clearTimeout(n),n=setTimeout(()=>{e.apply(this,r)},t)}}const pW=({text:e})=>C("div",{className:"NotMessageContent",children:ie("div",{children:["\u6CA1\u6709\u627E\u5230\u4E0E",ie("span",{className:"NotMessageContent-keyword",children:['"',e,'"']}),"\u76F8\u5173\u7684\u8BB0\u5F55"]})}),gW=e=>{const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState(!0),[i,a]=f.exports.useState([]),[l,s]=f.exports.useState("");f.exports.useEffect(()=>{t&&qB(e.info.UserName).then(b=>{let m=JSON.parse(b);a(m.Users),o(!1)})},[e.info,t]);const c=b=>{b.stopPropagation(),console.log("showModal"),n(!0),o(!0)},u=b=>{n(!1)},d=b=>{s(b)},v=f.exports.useCallback(oE(b=>{d(b)},400),[]),h=()=>{},g=b=>{n(!1),e.onClick&&e.onClick(b)},p=i.filter(b=>b.NickName.includes(l));return ie("div",{className:"ChattingRecords-ChatRoomUserList-Parent",children:[C("div",{onClick:c,children:e.children}),ie(js,{className:"ChattingRecords-ChatRoomUserList",overlayClassName:"ChattingRecords-ChatRoomUserList-Overlay",isOpen:t,onRequestClose:u,children:[C(eE,{onChange:v,selectTag:"",onClickClose:h}),r?C("div",{className:"ChattingRecords-ChatRoomUserList-Loading",children:"\u52A0\u8F7D\u4E2D..."}):C(hW,{userList:p,onClick:g})]})]})},hW=e=>ie("div",{className:"ChattingRecords-ChatRoomUserList-List",children:[e.userList.map(t=>C(mW,{info:t,onClick:()=>e.onClick(t)},Am())),C("div",{className:"ChattingRecords-ChatRoomUserList-List-End",children:"- \u5DF2\u7ECF\u5230\u5E95\u5566 -"})]}),mW=e=>ie("div",{className:"ChattingRecords-ChatRoomUserList-User",onClick:n=>{n.stopPropagation(),e.onClick&&e.onClick()},children:[C(Yo,{className:"ChattingRecords-ChatRoomUserList-Avatar",src:e.info.SmallHeadImgUrl,size:{xs:35,sm:35,md:35,lg:35,xl:35,xxl:35},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"}),C("div",{className:"ChattingRecords-ChatRoomUserList-Name",children:e.info.NickName})]});function yW(e){const[t,n]=f.exports.useState(!1);return ie("div",{className:"wechat-UserDialog-Bar",children:[C("div",{className:"wechat-UserDialog-text wechat-UserDialog-name",children:e.name}),ie("div",{className:"wechat-UserDialog-Bar-button-block",children:[ie("div",{className:"wechat-UserDialog-Bar-button-list",children:[C("div",{className:"wechat-UserDialog-Bar-button",title:"\u6700\u5C0F\u5316",onClick:()=>e.onClickButton("min"),children:C(RP,{className:"wechat-UserDialog-Bar-button-icon"})}),C("div",{className:"wechat-UserDialog-Bar-button",title:t?"\u8FD8\u539F":"\u6700\u5927\u5316",onClick:()=>{n(!t),e.onClickButton("max")},children:t?C(NP,{className:"wechat-UserDialog-Bar-button-icon"}):C(VP,{className:"wechat-UserDialog-Bar-button-icon"})}),C("div",{className:"wechat-UserDialog-Bar-button",title:"\u5173\u95ED",onClick:()=>e.onClickButton("close"),children:C(eo,{className:"wechat-UserDialog-Bar-button-icon"})})]}),C(vW,{info:e.info,onSelectMessage:e.onSelectMessage,onSelectDate:e.onSelectDate,children:e.name===""?C(Tt,{}):C("div",{className:"wechat-UserDialog-Bar-button wechat-UserDialog-Bar-button-msg",title:"\u804A\u5929\u8BB0\u5F55",onClick:()=>e.onClickButton("msg"),children:C($P,{className:"wechat-UserDialog-Bar-button-icon2"})})})]})]})}function bW(e){const{messages:t,prependMsgs:n,appendMsgs:r,setMsgs:o}=L$([]),[i,a]=f.exports.useState(e.info.Time),[l,s]=f.exports.useState("forward"),[c,u]=f.exports.useState(!1),[d,v]=f.exports.useState(!0),[h,g]=f.exports.useState(1),[p,b]=f.exports.useState(""),[m,y]=f.exports.useState(0),S=f.exports.useDeferredValue(t);f.exports.useEffect(()=>{e.info.UserName&&i>0&&(u(!0),p1(e.info.UserName,i,30,l).then(R=>{let P=JSON.parse(R);P.Total==0&&l=="forward"&&v(!1),console.log(P.Total,l);let N=[];P.Rows.forEach(I=>{N.unshift({_id:I.MsgSvrId,content:I,position:I.type===1e4?"middle":I.IsSender===1?"right":"left",user:{avatar:I.userInfo.SmallHeadImgUrl,name:I.userInfo.ReMark===""?I.userInfo.NickName:I.userInfo.ReMark},createdAt:I.createTime,key:I.MsgSvrId})}),u(!1),l==="backward"?r(N):n(N)}))},[e.info.UserName,l,i]),f.exports.useEffect(()=>{e.info.UserName&&m>0&&(u(!0),p1(e.info.UserName,m,1,"backward").then(R=>{let P=JSON.parse(R);P.Rows.length==1&&(g(N=>N+1),o([]),a(P.Rows[0].createTime),s("both"),b(P.Rows[0].MsgSvrId)),u(!1)}))},[e.info.UserName,m]);const x=()=>{Ts("fetchMoreData"),c||setTimeout(()=>{a(t[0].createdAt-1),s("forward"),b("")},100)},$=()=>{Ts("fetchMoreDataDown"),c||setTimeout(()=>{a(t[t.length-1].createdAt+1),s("backward"),b("")},100)},E=R=>{g(P=>P+1),o([]),a(R.createdAt),s("both"),b(R.key)},w=R=>{y(R)};return ie("div",{className:"wechat-UserDialog",children:[C(yW,{name:e.info.NickName===null?"":e.info.NickName,onClickButton:e.onClickButton,info:e.info,onSelectMessage:E,onSelectDate:w}),C(S9,{messages:S,fetchMoreData:x,hasMore:d&&!c,renderMessageContent:J$,scrollIntoId:p,atBottom:$},h)]})}function SW(){const[e,t]=f.exports.useState(0),[n,r]=f.exports.useState(1),[o,i]=f.exports.useState(!1),[a,l]=f.exports.useState(null),[s,c]=f.exports.useState({}),u=v=>{Ts(v),v==="setting"?i(!0):v==="exit"&&(r(n+1),t(h=>h+1))},d=v=>{switch(v){case"min":o9();break;case"max":r9();break;case"close":a9();break}};return f.exports.useEffect(()=>{t(1)},[]),f.exports.useEffect(()=>{if(e!=0)return e9(),_$("selfInfo",v=>{l(JSON.parse(v))}),()=>{A$("selfInfo")}},[e]),ie("div",{id:"App",children:[C(g9,{onClickItem:v=>{console.log(v),u(v)},Avatar:a?a.SmallHeadImgUrl:""}),C(d9,{selfName:a?a.UserName:"",onClickItem:v=>{c(v),Ts("click: "+v.UserName)}},n),C(bW,{info:s,onClickButton:d},s.UserName)]})}const CW=document.getElementById("root"),xW=AC(CW);js.setAppElement("#root");xW.render(C(lt.StrictMode,{children:C(SW,{})})); diff --git a/frontend/dist/assets/index.de7292ad.css b/frontend/dist/assets/index.de7292ad.css new file mode 100644 index 0000000..65557f2 --- /dev/null +++ b/frontend/dist/assets/index.de7292ad.css @@ -0,0 +1 @@ +@charset "UTF-8";html{background-color:#f5f5f5}body{margin:0;font-family:Nunito,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}@font-face{font-family:Nunito;font-style:normal;font-weight:400;src:local(""),url(/assets/nunito-v16-latin-regular.06f3af3f.woff2) format("woff2")}#app{height:100vh;text-align:center}#App{height:100vh;text-align:center;display:flex;flex-direction:row}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-thumb{--tw-border-opacity: 1;background-color:#b6b4b4cc;border-color:rgba(181,180,178,var(--tw-border-opacity));border-radius:9999px;border-width:1px}.wechat-UserList{width:275px;height:100%;background-color:#eae8e7}.wechat-SearchBar{height:60px;background-color:#f7f7f7;--wails-draggable:drag}.wechat-SearchBar-Input{height:26px;width:240px;background-color:#e6e6e6;margin-top:22px;--wails-draggable:no-drag}.wechat-UserList-Items{height:calc(100% - 60px);overflow:auto}.wechat-UserItem{display:flex;justify-content:space-between;height:64px}.wechat-UserItem{transition:background-color .3s ease}.wechat-UserItem:hover{background-color:#dcdad9}.wechat-UserItem:focus{background-color:#c9c8c6}.selectedItem{background-color:#c9c8c6}#wechat-UserItem-content-Avatar-id{border-radius:0}.wechat-UserItem-content-Avatar{margin-top:12px;margin-left:9px;margin-right:9px}.wechat-UserItem-content{flex:1;width:55%;display:flex;flex-direction:column;justify-content:space-between}.wechat-UserItem-content-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.wechat-UserItem-content-name{color:#000;font-size:95%;margin-top:12px}.wechat-UserItem-content-msg{color:#999;font-size:80%;margin-bottom:10px}.wechat-UserItem-date{color:#999;font-size:80%;margin-top:12px;margin-right:9px}.Setting-Modal{width:500px;background-color:#f5f5f5;position:fixed;top:35%;left:50%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.Setting-Modal-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.WechatInfoTable{display:flex;flex-direction:column;font-size:.9rem;border-top:1px solid #b9b9b9}.WechatInfoTable-column{display:flex;margin-top:8px}.WechatInfoTable-column-tag{margin-left:8px}.Setting-Modal-export-button{margin-top:10px}.Setting-Modal-button{position:absolute;top:10px;right:10px;padding:5px 10px;border:none;cursor:pointer}.Setting-Modal-confirm{background-color:#f5f5f5;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.Setting-Modal-confirm-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.Setting-Modal-confirm-title{text-align:center}.Setting-Modal-confirm-buttons{display:flex;gap:10px}.wechat-menu{display:flex;flex-direction:column;width:52px;justify-content:flex-start;height:100%;background-color:#2e2e2e;--wails-draggable:drag}.wechat-menu-item{margin-left:auto;margin-right:auto;margin-top:30px;--wails-draggable:no-drag}#wechat-menu-item-Avatar{border-radius:0}.wechat-menu-item-icon{background-color:#2e2e2e}.wechat-menu-selectedColor{color:#07c160}.ChatUi{background-color:#f3f3f3;height:calc(100% - 60px)}.ChatUiBar{display:flex;justify-content:space-between;align-items:center;padding:4% 2% 2%;border-bottom:.5px solid #dddbdb;background-color:#fff}.ChatUiBar--Text{flex:1;text-align:center;margin:1%}.ChatUiBar--Btn>.Icon{height:1.5em;width:1.5em}#scrollableDiv{height:100%;overflow:auto;display:flex;flex-direction:column-reverse}.MessageBubble{display:flex;flex-direction:column;justify-content:space-between;align-items:center;padding:10px}.MessageBubble>.Time{text-align:center;font-size:.8rem;margin-bottom:3px;background-color:#c9c8c6;color:#fff;padding:2px 3px;border-radius:4px}.MessageBubble-content-left{align-self:flex-start;display:flex;max-width:60%}.MessageBubble-content-right{align-self:flex-end;display:flex;max-width:60%}.Bubble-right>.Bubble{background-color:#95ec69}.MessageBubble-Avatar-left{margin-right:2px;border-radius:10%}.MessageBubble-Avatar-right{margin-left:2px;border-radius:10%}.Bubble-left{display:flex;flex-direction:column;align-items:flex-start;flex:1 1;max-width:100%}.MessageBubble-Name-left{color:#383838;font-size:small;margin-bottom:1px}.Bubble-right{display:flex;flex-direction:column;align-items:flex-end;flex:1 1;max-width:100%}.MessageBubble-Name-right{color:#383838;font-size:small;margin-bottom:1px}.CardMessageText{text-align:start;max-width:100%;word-break:break-all;padding:0}.MessageText-emoji{width:1.2rem;height:1.2rem;vertical-align:text-bottom}div.Bubble-right>div.CardMessageText{background-color:#95ec69}.System-Text{font-size:.8rem;color:#686868}.CardMessage{background-color:#fff;border-radius:3%;height:130px;width:260px;flex:1;display:flex;flex-direction:column;justify-content:space-between;text-align:start;padding:12px;cursor:pointer}.CardMessage-Content{display:flex;flex-direction:row;justify-content:space-between;max-width:100%;max-height:70%;padding-bottom:5px}.CardMessage-Title{overflow:hidden;text-overflow:ellipsis;word-break:break-all;max-width:95%}.CardMessage-Desc{overflow:hidden;text-overflow:ellipsis;max-width:80%;font-size:.75rem;height:90%;padding-top:5px;padding-bottom:5px;color:#949292}.CardMessage-Desc-Span{color:#bd0b0b}.CardMessageLink-Line{height:1px;width:100%;background-color:#f6f4f4}.CardMessageLink-Line-None{display:none}.CardMessageLink-Name{padding-top:4px;font-size:.65rem}.MessageRefer-Right{display:flex;flex-direction:column;align-items:flex-end}.MessageRefer-Left{display:flex;flex-direction:column;align-items:flex-start}.MessageRefer-Content{margin-top:6px;font-size:.8rem;color:#595959;background-color:#c9c8c6;border-radius:2px;padding:4px}.MessageRefer-Content-Text{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.CardMessageFile-Icon{font-size:45px;color:#595959}.CardMessage-Menu{font-size:.8rem}.CardMessageAudio{max-width:100%}.szh-menu{margin:0;padding:0;list-style:none;box-sizing:border-box;width:max-content;z-index:100;border:1px solid rgba(0,0,0,.1);background-color:#fff}.szh-menu:focus{outline:none}.szh-menu__arrow{box-sizing:border-box;width:.75rem;height:.75rem;background-color:#fff;border:1px solid transparent;border-left-color:#0000001a;border-top-color:#0000001a;z-index:-1}.szh-menu__arrow--dir-left{right:-.375rem;transform:translateY(-50%) rotate(135deg)}.szh-menu__arrow--dir-right{left:-.375rem;transform:translateY(-50%) rotate(-45deg)}.szh-menu__arrow--dir-top{bottom:-.375rem;transform:translate(-50%) rotate(-135deg)}.szh-menu__arrow--dir-bottom{top:-.375rem;transform:translate(-50%) rotate(45deg)}.szh-menu__item{cursor:pointer}.szh-menu__item:focus{outline:none}.szh-menu__item--hover{background-color:#ebebeb}.szh-menu__item--focusable{cursor:default;background-color:inherit}.szh-menu__item--disabled{cursor:default;color:#aaa}.szh-menu__group{box-sizing:border-box}.szh-menu__radio-group{margin:0;padding:0;list-style:none}.szh-menu__divider{height:1px;margin:.5rem 0;background-color:#0000001f}.szh-menu-button{box-sizing:border-box}.szh-menu{user-select:none;color:#212529;border:none;border-radius:.25rem;box-shadow:0 3px 7px #0002,0 .6px 2px #0000001a;min-width:10rem;padding:.5rem 0}.szh-menu__item{display:flex;align-items:center;position:relative;padding:.375rem 1.5rem}.szh-menu-container--itemTransition .szh-menu__item{transition-property:background-color,color;transition-duration:.15s;transition-timing-function:ease-in-out}.szh-menu__item--type-radio{padding-left:2.2rem}.szh-menu__item--type-radio:before{content:"\25cb";position:absolute;left:.8rem;top:.55rem;font-size:.8rem}.szh-menu__item--type-radio.szh-menu__item--checked:before{content:"\25cf"}.szh-menu__item--type-checkbox{padding-left:2.2rem}.szh-menu__item--type-checkbox:before{position:absolute;left:.8rem}.szh-menu__item--type-checkbox.szh-menu__item--checked:before{content:"\2714"}.szh-menu__submenu>.szh-menu__item{padding-right:2.5rem}.szh-menu__submenu>.szh-menu__item:after{content:"\276f";position:absolute;right:1rem}.szh-menu__header{color:#888;font-size:.8rem;padding:.2rem 1.5rem;text-transform:uppercase}.SearchInputIcon{background-color:#f5f4f4;display:flex;align-items:center}.SearchInputIcon-second{font-size:12px;margin:0 3px;cursor:default}#RecordsUiscrollableDiv{height:400px;overflow:auto;display:flex;flex-direction:column-reverse;border-top:1px solid #efefef}#RecordsUiscrollableDiv>div>div>.MessageBubble:hover{background-color:#dcdad9}.RecordsUi-MessageBubble>.MessageBubble-content-left{max-width:95%}.CalendarChoose{height:400px}.CalendarLoading{height:220px;padding-top:180px}.ChattingRecords-Modal{width:500px;background-color:#f5f5f5;position:fixed;top:45%;left:50%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.ChattingRecords-Modal-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.ChattingRecords-Modal-Bar-Tag{display:flex;flex-direction:row;justify-content:space-around;margin-top:5px;margin-bottom:5px;cursor:default;color:#576b95;font-size:.9rem}.ChattingRecords-Modal-Bar-Top{display:flex;flex-direction:row;justify-content:space-between;padding:0 5px 5px}.NotMessageContent{height:400px;display:flex;justify-content:center;align-items:center}.NotMessageContent-keyword{color:#07c160}.ChattingRecords-ChatRoomUserList{width:260px;height:300px;background-color:#f5f5f5;position:fixed;top:48%;left:70%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.ChattingRecords-ChatRoomUserList-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.ChattingRecords-ChatRoomUserList>.wechat-SearchInput{margin-bottom:10px}.ChattingRecords-ChatRoomUserList-List{overflow:auto;height:90%}.ChattingRecords-ChatRoomUserList-User{display:flex;padding-bottom:5px;align-items:center}.ChattingRecords-ChatRoomUserList-User:hover{background-color:#dcdad9}.ChattingRecords-ChatRoomUserList-Name{padding-left:8px;font-size:.85rem}.ChattingRecords-ChatRoomUserList-Loading{padding:20px;text-align:center}.ChattingRecords-ChatRoomUserList-List-End{padding:5px;text-align:center;font-size:.85rem}.wechat-UserDialog{flex-grow:1;background-color:#f5f5f5;flex:1;height:100%;display:flex;flex-direction:column;justify-content:space-between;width:calc(100% - 327px)}.wechat-UserDialog-Bar{height:60px;background-color:#f5f5f5;border-left:1px solid #E6E6E6;border-bottom:1px solid #E6E6E6;display:flex;flex-direction:row;justify-content:space-between;--wails-draggable:drag}.wechat-UserDialog-Bar-button-block{display:flex;flex-direction:column}.wechat-UserDialog-Bar-button-list{display:flex;flex-direction:row;--wails-draggable:no-drag}.wechat-UserDialog-Bar-button{width:34px;height:22px;color:#131212}.wechat-UserDialog-Bar-button-icon{width:12px;height:10px}.wechat-UserDialog-Bar-button-msg{margin-left:auto;margin-top:5px;--wails-draggable:no-drag}.wechat-UserDialog-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.wechat-UserDialog-name{color:#000;font-size:large;margin-top:20px;margin-left:16px;--wails-draggable:no-drag} diff --git a/frontend/dist/assets/nunito-v16-latin-regular.06f3af3f.woff2 b/frontend/dist/assets/nunito-v16-latin-regular.06f3af3f.woff2 new file mode 100644 index 0000000..2f9cc59 Binary files /dev/null and b/frontend/dist/assets/nunito-v16-latin-regular.06f3af3f.woff2 differ diff --git a/frontend/dist/index.html b/frontend/dist/index.html new file mode 100644 index 0000000..5a21f74 --- /dev/null +++ b/frontend/dist/index.html @@ -0,0 +1,15 @@ + + + + + + wechatDataBackup + + + + +
+ + + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..eab7e5e --- /dev/null +++ b/go.mod @@ -0,0 +1,70 @@ +module wechatDataBackup + +go 1.21 + +toolchain go1.21.0 + +require ( + github.com/beevik/etree v1.3.0 + github.com/mattn/go-sqlite3 v1.14.22 + github.com/pierrec/lz4 v2.6.1+incompatible + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 + github.com/shirou/gopsutil v2.21.11+incompatible + github.com/shirou/gopsutil/v3 v3.24.2 + github.com/spf13/viper v1.18.2 + github.com/wailsapp/wails/v2 v2.9.1 + golang.org/x/sys v0.20.0 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/bep/debounce v1.2.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/labstack/echo/v4 v4.10.2 // indirect + github.com/labstack/gommon v0.4.0 // indirect + github.com/leaanthony/go-ansi-parser v1.6.0 // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.6.0 // indirect + github.com/leaanthony/u v1.1.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/samber/lo v1.38.1 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/tkrajina/go-reflector v0.5.6 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/wailsapp/go-webview2 v1.0.10 // indirect + github.com/wailsapp/mimetype v1.4.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/text v0.15.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +// replace github.com/wailsapp/wails/v2 v2.8.0 => C:\Users\HAL\go\pkg\mod diff --git a/main.go b/main.go new file mode 100644 index 0000000..74987f2 --- /dev/null +++ b/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "embed" + "fmt" + "io" + "log" + "net/http" + "os" + "strings" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/assetserver" +) + +//go:embed all:frontend/dist +var assets embed.FS + +type FileLoader struct { + http.Handler +} + +func NewFileLoader() *FileLoader { + return &FileLoader{} +} + +func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) { + var err error + requestedFilename := strings.TrimPrefix(req.URL.Path, "/") + // println("Requesting file:", requestedFilename) + fileData, err := os.ReadFile(requestedFilename) + if err != nil { + res.WriteHeader(http.StatusBadRequest) + res.Write([]byte(fmt.Sprintf("Could not load file %s", requestedFilename))) + } + + res.Write(fileData) +} + +func init() { + log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile) +} + +func main() { + file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + defer file.Close() + + multiWriter := io.MultiWriter(file, os.Stdout) + // 设置日志输出目标为文件 + log.SetOutput(multiWriter) + log.Println("====================== wechatDataBackup ======================") + // Create an instance of the app structure + app := NewApp() + + // Create application with options + err := wails.Run(&options.App{ + Title: "wechatDataBackup", + MinWidth: 800, + MinHeight: 600, + Width: 1024, + Height: 768, + AssetServer: &assetserver.Options{ + Assets: assets, + Handler: NewFileLoader(), + }, + BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, + OnStartup: app.startup, + OnBeforeClose: app.beforeClose, + Bind: []interface{}{ + app, + }, + Frameless: true, + }) + + if err != nil { + println("Error:", err.Error()) + } +} diff --git a/pkg/lame/.gitignore b/pkg/lame/.gitignore new file mode 100644 index 0000000..8365624 --- /dev/null +++ b/pkg/lame/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/pkg/lame/LICENSE b/pkg/lame/LICENSE new file mode 100644 index 0000000..63280d0 --- /dev/null +++ b/pkg/lame/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Pavel Vorobyov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pkg/lame/README.md b/pkg/lame/README.md new file mode 100644 index 0000000..b618755 --- /dev/null +++ b/pkg/lame/README.md @@ -0,0 +1,43 @@ +lame +==== + +Simple libmp3lame powered mp3 encoder for Go + +**Note:** this project is obsolete, consider moving to https://github.com/viert/go-lame + +Example: + +```Go +package main + +import ( + "bufio" + "lame" + "os" +) + +func main() { + f, err := os.Open("input.raw") + if err != nil { + panic(err) + } + defer f.Close() + reader := bufio.NewReader(f) + + of, err := os.Create("output.mp3") + if err != nil { + panic(err) + } + defer of.Close() + + wr := lame.NewWriter(of) + wr.Encoder.SetBitrate(112) + wr.Encoder.SetQuality(1) + + // IMPORTANT! + wr.Encoder.InitParams() + + reader.WriteTo(wr) + +} +``` diff --git a/pkg/lame/clame/VbrTag.c b/pkg/lame/clame/VbrTag.c new file mode 100644 index 0000000..5800a44 --- /dev/null +++ b/pkg/lame/clame/VbrTag.c @@ -0,0 +1,1082 @@ +/* + * Xing VBR tagging for LAME. + * + * Copyright (c) 1999 A.L. Faber + * Copyright (c) 2001 Jonathan Dee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: VbrTag.c,v 1.106 2017/08/06 18:15:47 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "bitstream.h" +#include "VbrTag.h" +#include "lame_global_flags.h" +#include "tables.h" + +#ifdef __sun__ +/* woraround for SunOS 4.x, it has SEEK_* defined here */ +#include +#endif + + +#ifdef _DEBUG +/* #define DEBUG_VBRTAG */ +#endif + +/* + * 4 bytes for Header Tag + * 4 bytes for Header Flags + * 100 bytes for entry (NUMTOCENTRIES) + * 4 bytes for FRAME SIZE + * 4 bytes for STREAM_SIZE + * 4 bytes for VBR SCALE. a VBR quality indicator: 0=best 100=worst + * 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)" + * ___________ + * 140 bytes +*/ +#define VBRHEADERSIZE (NUMTOCENTRIES+4+4+4+4+4) + +#define LAMEHEADERSIZE (VBRHEADERSIZE + 9 + 1 + 1 + 8 + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2) + +/* the size of the Xing header (MPEG1 and MPEG2) in kbps */ +#define XING_BITRATE1 128 +#define XING_BITRATE2 64 +#define XING_BITRATE25 32 + +extern const char* get_lame_tag_encoder_short_version(void); + +static const char VBRTag0[] = { "Xing" }; +static const char VBRTag1[] = { "Info" }; + + + + +/* Lookup table for fast CRC computation + * See 'CRC_update_lookup' + * Uses the polynomial x^16+x^15+x^2+1 */ + +static const unsigned int crc16_lookup[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + + + + + +/*********************************************************************** + * Robert Hegemann 2001-01-17 + ***********************************************************************/ + +static void +addVbr(VBR_seek_info_t * v, int bitrate) +{ + int i; + + v->nVbrNumFrames++; + v->sum += bitrate; + v->seen++; + + if (v->seen < v->want) { + return; + } + + if (v->pos < v->size) { + v->bag[v->pos] = v->sum; + v->pos++; + v->seen = 0; + } + if (v->pos == v->size) { + for (i = 1; i < v->size; i += 2) { + v->bag[i / 2] = v->bag[i]; + } + v->want *= 2; + v->pos /= 2; + } +} + +static void +Xing_seek_table(VBR_seek_info_t const* v, unsigned char *t) +{ + int i, indx; + int seek_point; + + if (v->pos <= 0) + return; + + for (i = 1; i < NUMTOCENTRIES; ++i) { + float j = i / (float) NUMTOCENTRIES, act, sum; + indx = (int) (floor(j * v->pos)); + if (indx > v->pos - 1) + indx = v->pos - 1; + act = v->bag[indx]; + sum = v->sum; + seek_point = (int) (256. * act / sum); + if (seek_point > 255) + seek_point = 255; + t[i] = seek_point; + } +} + +#ifdef DEBUG_VBR_SEEKING_TABLE +static void +print_seeking(unsigned char *t) +{ + int i; + + printf("seeking table "); + for (i = 0; i < NUMTOCENTRIES; ++i) { + printf(" %d ", t[i]); + } + printf("\n"); +} +#endif + + +/**************************************************************************** + * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries + * Paramters: + * nStreamPos: how many bytes did we write to the bitstream so far + * (in Bytes NOT Bits) + **************************************************************************** +*/ +void +AddVbrFrame(lame_internal_flags * gfc) +{ + int kbps = bitrate_table[gfc->cfg.version][gfc->ov_enc.bitrate_index]; + assert(gfc->VBR_seek_table.bag); + addVbr(&gfc->VBR_seek_table, kbps); +} + + +/*-------------------------------------------------------------*/ +static int +ExtractI4(const unsigned char *buf) +{ + int x; + /* big endian extract */ + x = buf[0]; + x <<= 8; + x |= buf[1]; + x <<= 8; + x |= buf[2]; + x <<= 8; + x |= buf[3]; + return x; +} + +static void +CreateI4(unsigned char *buf, uint32_t nValue) +{ + /* big endian create */ + buf[0] = (nValue >> 24) & 0xff; + buf[1] = (nValue >> 16) & 0xff; + buf[2] = (nValue >> 8) & 0xff; + buf[3] = (nValue) & 0xff; +} + + + +static void +CreateI2(unsigned char *buf, int nValue) +{ + /* big endian create */ + buf[0] = (nValue >> 8) & 0xff; + buf[1] = (nValue) & 0xff; +} + +/* check for magic strings*/ +static int +IsVbrTag(const unsigned char *buf) +{ + int isTag0, isTag1; + + isTag0 = ((buf[0] == VBRTag0[0]) && (buf[1] == VBRTag0[1]) && (buf[2] == VBRTag0[2]) + && (buf[3] == VBRTag0[3])); + isTag1 = ((buf[0] == VBRTag1[0]) && (buf[1] == VBRTag1[1]) && (buf[2] == VBRTag1[2]) + && (buf[3] == VBRTag1[3])); + + return (isTag0 || isTag1); +} + +#define SHIFT_IN_BITS_VALUE(x,n,v) ( x = (x << (n)) | ( (v) & ~(-1 << (n)) ) ) + +static void +setLameTagFrameHeader(lame_internal_flags const *gfc, unsigned char *buffer) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + char abyte, bbyte; + + SHIFT_IN_BITS_VALUE(buffer[0], 8u, 0xffu); + + SHIFT_IN_BITS_VALUE(buffer[1], 3u, 7); + SHIFT_IN_BITS_VALUE(buffer[1], 1u, (cfg->samplerate_out < 16000) ? 0 : 1); + SHIFT_IN_BITS_VALUE(buffer[1], 1u, cfg->version); + SHIFT_IN_BITS_VALUE(buffer[1], 2u, 4 - 3); + SHIFT_IN_BITS_VALUE(buffer[1], 1u, (!cfg->error_protection) ? 1 : 0); + + SHIFT_IN_BITS_VALUE(buffer[2], 4u, eov->bitrate_index); + SHIFT_IN_BITS_VALUE(buffer[2], 2u, cfg->samplerate_index); + SHIFT_IN_BITS_VALUE(buffer[2], 1u, 0); + SHIFT_IN_BITS_VALUE(buffer[2], 1u, cfg->extension); + + SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->mode); + SHIFT_IN_BITS_VALUE(buffer[3], 2u, eov->mode_ext); + SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->copyright); + SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->original); + SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->emphasis); + + /* the default VBR header. 48 kbps layer III, no padding, no crc */ + /* but sampling freq, mode andy copyright/copy protection taken */ + /* from first valid frame */ + buffer[0] = (uint8_t) 0xff; + abyte = (buffer[1] & (unsigned char) 0xf1); + { + int bitrate; + if (1 == cfg->version) { + bitrate = XING_BITRATE1; + } + else { + if (cfg->samplerate_out < 16000) + bitrate = XING_BITRATE25; + else + bitrate = XING_BITRATE2; + } + + if (cfg->vbr == vbr_off) + bitrate = cfg->avg_bitrate; + + if (cfg->free_format) + bbyte = 0x00; + else + bbyte = 16 * BitrateIndex(bitrate, cfg->version, cfg->samplerate_out); + } + + /* Use as much of the info from the real frames in the + * Xing header: samplerate, channels, crc, etc... + */ + if (cfg->version == 1) { + /* MPEG1 */ + buffer[1] = abyte | (char) 0x0a; /* was 0x0b; */ + abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */ + buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG1 frame */ + } + else { + /* MPEG2 */ + buffer[1] = abyte | (char) 0x02; /* was 0x03; */ + abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */ + buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG2 frame */ + } +} + +#if 0 +static int CheckVbrTag(unsigned char *buf); + +/*-------------------------------------------------------------*/ +/* Same as GetVbrTag below, but only checks for the Xing tag. + requires buf to contain only 40 bytes */ +/*-------------------------------------------------------------*/ +int +CheckVbrTag(unsigned char *buf) +{ + int h_id, h_mode; + + /* get selected MPEG header data */ + h_id = (buf[1] >> 3) & 1; + h_mode = (buf[3] >> 6) & 3; + + /* determine offset of header */ + if (h_id) { + /* mpeg1 */ + if (h_mode != 3) + buf += (32 + 4); + else + buf += (17 + 4); + } + else { + /* mpeg2 */ + if (h_mode != 3) + buf += (17 + 4); + else + buf += (9 + 4); + } + + return IsVbrTag(buf); +} +#endif + +int +GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf) +{ + int i, head_flags; + int h_bitrate, h_id, h_mode, h_sr_index, h_layer; + int enc_delay, enc_padding; + + /* get Vbr header data */ + pTagData->flags = 0; + + /* get selected MPEG header data */ + h_layer = (buf[1] >> 1) & 3; + if ( h_layer != 0x01 ) { + /* the following code assumes Layer-3, so give up here */ + return 0; + } + h_id = (buf[1] >> 3) & 1; + h_sr_index = (buf[2] >> 2) & 3; + h_mode = (buf[3] >> 6) & 3; + h_bitrate = ((buf[2] >> 4) & 0xf); + h_bitrate = bitrate_table[h_id][h_bitrate]; + + /* check for FFE syncword */ + if ((buf[1] >> 4) == 0xE) + pTagData->samprate = samplerate_table[2][h_sr_index]; + else + pTagData->samprate = samplerate_table[h_id][h_sr_index]; + /* if( h_id == 0 ) */ + /* pTagData->samprate >>= 1; */ + + + + /* determine offset of header */ + if (h_id) { + /* mpeg1 */ + if (h_mode != 3) + buf += (32 + 4); + else + buf += (17 + 4); + } + else { + /* mpeg2 */ + if (h_mode != 3) + buf += (17 + 4); + else + buf += (9 + 4); + } + + if (!IsVbrTag(buf)) + return 0; + + buf += 4; + + pTagData->h_id = h_id; + + head_flags = pTagData->flags = ExtractI4(buf); + buf += 4; /* get flags */ + + if (head_flags & FRAMES_FLAG) { + pTagData->frames = ExtractI4(buf); + buf += 4; + } + + if (head_flags & BYTES_FLAG) { + pTagData->bytes = ExtractI4(buf); + buf += 4; + } + + if (head_flags & TOC_FLAG) { + if (pTagData->toc != NULL) { + for (i = 0; i < NUMTOCENTRIES; i++) + pTagData->toc[i] = buf[i]; + } + buf += NUMTOCENTRIES; + } + + pTagData->vbr_scale = -1; + + if (head_flags & VBR_SCALE_FLAG) { + pTagData->vbr_scale = ExtractI4(buf); + buf += 4; + } + + pTagData->headersize = ((h_id + 1) * 72000 * h_bitrate) / pTagData->samprate; + + buf += 21; + enc_delay = buf[0] << 4; + enc_delay += buf[1] >> 4; + enc_padding = (buf[1] & 0x0F) << 8; + enc_padding += buf[2]; + /* check for reasonable values (this may be an old Xing header, */ + /* not a INFO tag) */ + if (enc_delay < 0 || enc_delay > 3000) + enc_delay = -1; + if (enc_padding < 0 || enc_padding > 3000) + enc_padding = -1; + + pTagData->enc_delay = enc_delay; + pTagData->enc_padding = enc_padding; + +#ifdef DEBUG_VBRTAG + fprintf(stderr, "\n\n********************* VBR TAG INFO *****************\n"); + fprintf(stderr, "tag :%s\n", VBRTag); + fprintf(stderr, "head_flags :%d\n", head_flags); + fprintf(stderr, "bytes :%d\n", pTagData->bytes); + fprintf(stderr, "frames :%d\n", pTagData->frames); + fprintf(stderr, "VBR Scale :%d\n", pTagData->vbr_scale); + fprintf(stderr, "enc_delay = %i \n", enc_delay); + fprintf(stderr, "enc_padding= %i \n", enc_padding); + fprintf(stderr, "toc:\n"); + if (pTagData->toc != NULL) { + for (i = 0; i < NUMTOCENTRIES; i++) { + if ((i % 10) == 0) + fprintf(stderr, "\n"); + fprintf(stderr, " %3d", (int) (pTagData->toc[i])); + } + } + fprintf(stderr, "\n***************** END OF VBR TAG INFO ***************\n"); +#endif + return 1; /* success */ +} + + +/**************************************************************************** + * InitVbrTag: Initializes the header, and write empty frame to stream + * Paramters: + * fpStream: pointer to output file stream + * nMode : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO + **************************************************************************** +*/ +int +InitVbrTag(lame_global_flags * gfp) +{ + lame_internal_flags *gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + int kbps_header; + +#define MAXFRAMESIZE 2880 /* or 0xB40, the max freeformat 640 32kHz framesize */ + + /* + * Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz). + * (at 48kHz they use 56kbs since 48kbs frame not big enough for + * table of contents) + * let's always embed Xing header inside a 64kbs layer III frame. + * this gives us enough room for a LAME version string too. + * size determined by sampling frequency (MPEG1) + * 32kHz: 216 bytes@48kbs 288bytes@ 64kbs + * 44.1kHz: 156 bytes 208bytes@64kbs (+1 if padding = 1) + * 48kHz: 144 bytes 192 + * + * MPEG 2 values are the same since the framesize and samplerate + * are each reduced by a factor of 2. + */ + + + if (1 == cfg->version) { + kbps_header = XING_BITRATE1; + } + else { + if (cfg->samplerate_out < 16000) + kbps_header = XING_BITRATE25; + else + kbps_header = XING_BITRATE2; + } + + if (cfg->vbr == vbr_off) + kbps_header = cfg->avg_bitrate; + + /** make sure LAME Header fits into Frame + */ + { + int total_frame_size = ((cfg->version + 1) * 72000 * kbps_header) / cfg->samplerate_out; + int header_size = (cfg->sideinfo_len + LAMEHEADERSIZE); + gfc->VBR_seek_table.TotalFrameSize = total_frame_size; + if (total_frame_size < header_size || total_frame_size > MAXFRAMESIZE) { + /* disable tag, it wont fit */ + gfc->cfg.write_lame_tag = 0; + return 0; + } + } + + gfc->VBR_seek_table.nVbrNumFrames = 0; + gfc->VBR_seek_table.nBytesWritten = 0; + gfc->VBR_seek_table.sum = 0; + + gfc->VBR_seek_table.seen = 0; + gfc->VBR_seek_table.want = 1; + gfc->VBR_seek_table.pos = 0; + + if (gfc->VBR_seek_table.bag == NULL) { + gfc->VBR_seek_table.bag = lame_calloc(int, 400); + if (gfc->VBR_seek_table.bag != NULL) { + gfc->VBR_seek_table.size = 400; + } + else { + gfc->VBR_seek_table.size = 0; + ERRORF(gfc, "Error: can't allocate VbrFrames buffer\n"); + gfc->cfg.write_lame_tag = 0; + return -1; + } + } + + /* write dummy VBR tag of all 0's into bitstream */ + { + uint8_t buffer[MAXFRAMESIZE]; + size_t i, n; + + memset(buffer, 0, sizeof(buffer)); + setLameTagFrameHeader(gfc, buffer); + n = gfc->VBR_seek_table.TotalFrameSize; + for (i = 0; i < n; ++i) { + add_dummy_byte(gfc, buffer[i], 1); + } + } + /* Success */ + return 0; +} + + + +/* fast CRC-16 computation - uses table crc16_lookup 8*/ +static uint16_t +CRC_update_lookup(uint16_t value, uint16_t crc) +{ + uint16_t tmp; + tmp = crc ^ value; + crc = (crc >> 8) ^ crc16_lookup[tmp & 0xff]; + return crc; +} + +void +UpdateMusicCRC(uint16_t * crc, unsigned char const *buffer, int size) +{ + int i; + for (i = 0; i < size; ++i) + *crc = CRC_update_lookup(buffer[i], *crc); +} + + + + + +/**************************************************************************** + * Jonathan Dee 2001/08/31 + * + * PutLameVBR: Write LAME info: mini version + info on various switches used + * Paramters: + * pbtStreamBuffer : pointer to output buffer + * id3v2size : size of id3v2 tag in bytes + * crc : computation of crc-16 of Lame Tag so far (starting at frame sync) + * + **************************************************************************** +*/ +static int +PutLameVBR(lame_global_flags const *gfp, size_t nMusicLength, uint8_t * pbtStreamBuffer, uint16_t crc) +{ + lame_internal_flags const *gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + + int nBytesWritten = 0; + int i; + + int enc_delay = gfc->ov_enc.encoder_delay; /* encoder delay */ + int enc_padding = gfc->ov_enc.encoder_padding; /* encoder padding */ + + /*recall: cfg->vbr_q is for example set by the switch -V */ + /* gfp->quality by -q, -h, -f, etc */ + + int nQuality = (100 - 10 * gfp->VBR_q - gfp->quality); + + + /* + NOTE: + Even though the specification for the LAME VBR tag + did explicitly mention other encoders than LAME, + many SW/HW decoder seem to be able to make use of + this tag only, if the encoder version starts with LAME. + To be compatible with such decoders, ANY encoder will + be forced to write a fake LAME version string! + As a result, the encoder version info becomes worthless. + */ + const char *szVersion = get_lame_tag_encoder_short_version(); + uint8_t nVBR; + uint8_t nRevision = 0x00; + uint8_t nRevMethod; + uint8_t vbr_type_translator[] = { 1, 5, 3, 2, 4, 0, 3 }; /*numbering different in vbr_mode vs. Lame tag */ + + uint8_t nLowpass = + (((cfg->lowpassfreq / 100.0) + .5) > 255 ? 255 : (cfg->lowpassfreq / 100.0) + .5); + + uint32_t nPeakSignalAmplitude = 0; + + uint16_t nRadioReplayGain = 0; + uint16_t nAudiophileReplayGain = 0; + + uint8_t nNoiseShaping = cfg->noise_shaping; + uint8_t nStereoMode = 0; + int bNonOptimal = 0; + uint8_t nSourceFreq = 0; + uint8_t nMisc = 0; + uint16_t nMusicCRC = 0; + + /*psy model type: Gpsycho or NsPsytune */ + unsigned char bExpNPsyTune = 1; /* only NsPsytune */ + unsigned char bSafeJoint = (cfg->use_safe_joint_stereo) != 0; + + unsigned char bNoGapMore = 0; + unsigned char bNoGapPrevious = 0; + + int nNoGapCount = gfp->nogap_total; + int nNoGapCurr = gfp->nogap_current; + + + uint8_t nAthType = cfg->ATHtype; /*4 bits. */ + + uint8_t nFlags = 0; + + /* if ABR, {store bitrate <=255} else { store "-b"} */ + int nABRBitrate; + switch (cfg->vbr) { + case vbr_abr:{ + nABRBitrate = cfg->vbr_avg_bitrate_kbps; + break; + } + case vbr_off:{ + nABRBitrate = cfg->avg_bitrate; + break; + } + default:{ /*vbr modes */ + nABRBitrate = bitrate_table[cfg->version][cfg->vbr_min_bitrate_index];; + } + } + + + /*revision and vbr method */ + if (cfg->vbr < sizeof(vbr_type_translator)) + nVBR = vbr_type_translator[cfg->vbr]; + else + nVBR = 0x00; /*unknown. */ + + nRevMethod = 0x10 * nRevision + nVBR; + + + /* ReplayGain */ + if (cfg->findReplayGain) { + int RadioGain = gfc->ov_rpg.RadioGain; + if (RadioGain > 0x1FE) + RadioGain = 0x1FE; + if (RadioGain < -0x1FE) + RadioGain = -0x1FE; + + nRadioReplayGain = 0x2000; /* set name code */ + nRadioReplayGain |= 0xC00; /* set originator code to `determined automatically' */ + + if (RadioGain >= 0) + nRadioReplayGain |= RadioGain; /* set gain adjustment */ + else { + nRadioReplayGain |= 0x200; /* set the sign bit */ + nRadioReplayGain |= -RadioGain; /* set gain adjustment */ + } + } + + /* peak sample */ + if (cfg->findPeakSample) + nPeakSignalAmplitude = + abs((int) ((((FLOAT) gfc->ov_rpg.PeakSample) / 32767.0) * pow(2, 23) + .5)); + + /*nogap */ + if (nNoGapCount != -1) { + if (nNoGapCurr > 0) + bNoGapPrevious = 1; + + if (nNoGapCurr < nNoGapCount - 1) + bNoGapMore = 1; + } + + /*flags */ + + nFlags = nAthType + (bExpNPsyTune << 4) + + (bSafeJoint << 5) + + (bNoGapMore << 6) + + (bNoGapPrevious << 7); + + + if (nQuality < 0) + nQuality = 0; + + /*stereo mode field... a bit ugly. */ + + switch (cfg->mode) { + case MONO: + nStereoMode = 0; + break; + case STEREO: + nStereoMode = 1; + break; + case DUAL_CHANNEL: + nStereoMode = 2; + break; + case JOINT_STEREO: + if (cfg->force_ms) + nStereoMode = 4; + else + nStereoMode = 3; + break; + case NOT_SET: + /* FALLTHROUGH */ + default: + nStereoMode = 7; + break; + } + + /*Intensity stereo : nStereoMode = 6. IS is not implemented */ + + if (cfg->samplerate_in <= 32000) + nSourceFreq = 0x00; + else if (cfg->samplerate_in == 48000) + nSourceFreq = 0x02; + else if (cfg->samplerate_in > 48000) + nSourceFreq = 0x03; + else + nSourceFreq = 0x01; /*default is 44100Hz. */ + + + /*Check if the user overrided the default LAME behaviour with some nasty options */ + + if (cfg->short_blocks == short_block_forced || cfg->short_blocks == short_block_dispensed || ((cfg->lowpassfreq == -1) && (cfg->highpassfreq == -1)) || /* "-k" */ + (cfg->disable_reservoir && cfg->avg_bitrate < 320) || + cfg->noATH || cfg->ATHonly || (nAthType == 0) || cfg->samplerate_in <= 32000) + bNonOptimal = 1; + + nMisc = nNoiseShaping + (nStereoMode << 2) + + (bNonOptimal << 5) + + (nSourceFreq << 6); + + + nMusicCRC = gfc->nMusicCRC; + + + /*Write all this information into the stream */ + CreateI4(&pbtStreamBuffer[nBytesWritten], nQuality); + nBytesWritten += 4; + + strncpy((char *) &pbtStreamBuffer[nBytesWritten], szVersion, 9); + nBytesWritten += 9; + + pbtStreamBuffer[nBytesWritten] = nRevMethod; + nBytesWritten++; + + pbtStreamBuffer[nBytesWritten] = nLowpass; + nBytesWritten++; + + CreateI4(&pbtStreamBuffer[nBytesWritten], nPeakSignalAmplitude); + nBytesWritten += 4; + + CreateI2(&pbtStreamBuffer[nBytesWritten], nRadioReplayGain); + nBytesWritten += 2; + + CreateI2(&pbtStreamBuffer[nBytesWritten], nAudiophileReplayGain); + nBytesWritten += 2; + + pbtStreamBuffer[nBytesWritten] = nFlags; + nBytesWritten++; + + if (nABRBitrate >= 255) + pbtStreamBuffer[nBytesWritten] = 0xFF; + else + pbtStreamBuffer[nBytesWritten] = nABRBitrate; + nBytesWritten++; + + pbtStreamBuffer[nBytesWritten] = enc_delay >> 4; /* works for win32, does it for unix? */ + pbtStreamBuffer[nBytesWritten + 1] = (enc_delay << 4) + (enc_padding >> 8); + pbtStreamBuffer[nBytesWritten + 2] = enc_padding; + + nBytesWritten += 3; + + pbtStreamBuffer[nBytesWritten] = nMisc; + nBytesWritten++; + + + pbtStreamBuffer[nBytesWritten++] = 0; /*unused in rev0 */ + + CreateI2(&pbtStreamBuffer[nBytesWritten], cfg->preset); + nBytesWritten += 2; + + CreateI4(&pbtStreamBuffer[nBytesWritten], (int) nMusicLength); + nBytesWritten += 4; + + CreateI2(&pbtStreamBuffer[nBytesWritten], nMusicCRC); + nBytesWritten += 2; + + /*Calculate tag CRC.... must be done here, since it includes + *previous information*/ + + for (i = 0; i < nBytesWritten; i++) + crc = CRC_update_lookup(pbtStreamBuffer[i], crc); + + CreateI2(&pbtStreamBuffer[nBytesWritten], crc); + nBytesWritten += 2; + + return nBytesWritten; +} + +static long +skipId3v2(FILE * fpStream) +{ + size_t nbytes; + long id3v2TagSize; + unsigned char id3v2Header[10]; + + /* seek to the beginning of the stream */ + if (fseek(fpStream, 0, SEEK_SET) != 0) { + return -2; /* not seekable, abort */ + } + /* read 10 bytes in case there's an ID3 version 2 header here */ + nbytes = fread(id3v2Header, 1, sizeof(id3v2Header), fpStream); + if (nbytes != sizeof(id3v2Header)) { + return -3; /* not readable, maybe opened Write-Only */ + } + /* does the stream begin with the ID3 version 2 file identifier? */ + if (!strncmp((char *) id3v2Header, "ID3", 3)) { + /* the tag size (minus the 10-byte header) is encoded into four + * bytes where the most significant bit is clear in each byte */ + id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21) + | ((id3v2Header[7] & 0x7f) << 14) + | ((id3v2Header[8] & 0x7f) << 7) + | (id3v2Header[9] & 0x7f)) + + sizeof id3v2Header; + } + else { + /* no ID3 version 2 tag in this stream */ + id3v2TagSize = 0; + } + return id3v2TagSize; +} + + + +size_t +lame_get_lametag_frame(lame_global_flags const *gfp, unsigned char *buffer, size_t size) +{ + lame_internal_flags *gfc; + SessionConfig_t const *cfg; + unsigned long stream_size; + unsigned int nStreamIndex; + uint8_t btToc[NUMTOCENTRIES]; + + if (gfp == 0) { + return 0; + } + gfc = gfp->internal_flags; + if (gfc == 0) { + return 0; + } + if (!is_lame_internal_flags_valid(gfc)) { + return 0; + } + cfg = &gfc->cfg; + if (cfg->write_lame_tag == 0) { + return 0; + } + if (gfc->VBR_seek_table.pos <= 0) { + return 0; + } + if (size < gfc->VBR_seek_table.TotalFrameSize) { + return gfc->VBR_seek_table.TotalFrameSize; + } + if (buffer == 0) { + return 0; + } + + memset(buffer, 0, gfc->VBR_seek_table.TotalFrameSize); + + /* 4 bytes frame header */ + + setLameTagFrameHeader(gfc, buffer); + + /* Clear all TOC entries */ + memset(btToc, 0, sizeof(btToc)); + + if (cfg->free_format) { + int i; + for (i = 1; i < NUMTOCENTRIES; ++i) + btToc[i] = 255 * i / 100; + } + else { + Xing_seek_table(&gfc->VBR_seek_table, btToc); + } +#ifdef DEBUG_VBR_SEEKING_TABLE + print_seeking(btToc); +#endif + + /* Start writing the tag after the zero frame */ + nStreamIndex = cfg->sideinfo_len; + /* note! Xing header specifies that Xing data goes in the + * ancillary data with NO ERROR PROTECTION. If error protecton + * in enabled, the Xing data still starts at the same offset, + * and now it is in sideinfo data block, and thus will not + * decode correctly by non-Xing tag aware players */ + if (cfg->error_protection) + nStreamIndex -= 2; + + /* Put Vbr tag */ + if (cfg->vbr == vbr_off) { + buffer[nStreamIndex++] = VBRTag1[0]; + buffer[nStreamIndex++] = VBRTag1[1]; + buffer[nStreamIndex++] = VBRTag1[2]; + buffer[nStreamIndex++] = VBRTag1[3]; + + } + else { + buffer[nStreamIndex++] = VBRTag0[0]; + buffer[nStreamIndex++] = VBRTag0[1]; + buffer[nStreamIndex++] = VBRTag0[2]; + buffer[nStreamIndex++] = VBRTag0[3]; + } + + /* Put header flags */ + CreateI4(&buffer[nStreamIndex], FRAMES_FLAG + BYTES_FLAG + TOC_FLAG + VBR_SCALE_FLAG); + nStreamIndex += 4; + + /* Put Total Number of frames */ + CreateI4(&buffer[nStreamIndex], gfc->VBR_seek_table.nVbrNumFrames); + nStreamIndex += 4; + + /* Put total audio stream size, including Xing/LAME Header */ + stream_size = gfc->VBR_seek_table.nBytesWritten + gfc->VBR_seek_table.TotalFrameSize; + CreateI4(&buffer[nStreamIndex], stream_size); + nStreamIndex += 4; + + /* Put TOC */ + memcpy(&buffer[nStreamIndex], btToc, sizeof(btToc)); + nStreamIndex += sizeof(btToc); + + + if (cfg->error_protection) { + /* (jo) error_protection: add crc16 information to header */ + CRC_writeheader(gfc, (char *) buffer); + } + { + /*work out CRC so far: initially crc = 0 */ + uint16_t crc = 0x00; + unsigned int i; + for (i = 0; i < nStreamIndex; i++) + crc = CRC_update_lookup(buffer[i], crc); + /*Put LAME VBR info */ + nStreamIndex += PutLameVBR(gfp, stream_size, buffer + nStreamIndex, crc); + } + +#ifdef DEBUG_VBRTAG + { + VBRTAGDATA TestHeader; + GetVbrTag(&TestHeader, buffer); + } +#endif + + return gfc->VBR_seek_table.TotalFrameSize; +} + +/*********************************************************************** + * + * PutVbrTag: Write final VBR tag to the file + * Paramters: + * lpszFileName: filename of MP3 bit stream + * nVbrScale : encoder quality indicator (0..100) + **************************************************************************** + */ + +int +PutVbrTag(lame_global_flags const *gfp, FILE * fpStream) +{ + lame_internal_flags *gfc = gfp->internal_flags; + + long lFileSize; + long id3v2TagSize; + size_t nbytes; + uint8_t buffer[MAXFRAMESIZE]; + + if (gfc->VBR_seek_table.pos <= 0) + return -1; + + /* Seek to end of file */ + fseek(fpStream, 0, SEEK_END); + + /* Get file size */ + lFileSize = ftell(fpStream); + + /* Abort if file has zero length. Yes, it can happen :) */ + if (lFileSize == 0) + return -1; + + /* + * The VBR tag may NOT be located at the beginning of the stream. + * If an ID3 version 2 tag was added, then it must be skipped to write + * the VBR tag data. + */ + + id3v2TagSize = skipId3v2(fpStream); + + if (id3v2TagSize < 0) { + return id3v2TagSize; + } + + /*Seek to the beginning of the stream */ + fseek(fpStream, id3v2TagSize, SEEK_SET); + + nbytes = lame_get_lametag_frame(gfp, buffer, sizeof(buffer)); + if (nbytes > sizeof(buffer)) { + return -1; + } + + if (nbytes < 1) { + return 0; + } + + /* Put it all to disk again */ + if (fwrite(buffer, nbytes, 1, fpStream) != 1) { + return -1; + } + + return 0; /* success */ +} diff --git a/pkg/lame/clame/VbrTag.h b/pkg/lame/clame/VbrTag.h new file mode 100644 index 0000000..406af36 --- /dev/null +++ b/pkg/lame/clame/VbrTag.h @@ -0,0 +1,79 @@ +/* + * Xing VBR tagging for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_VRBTAG_H +#define LAME_VRBTAG_H + + +/* ----------------------------------------------------------- + * A Vbr header may be present in the ancillary + * data field of the first frame of an mp3 bitstream + * The Vbr header (optionally) contains + * frames total number of audio frames in the bitstream + * bytes total number of bytes in the bitstream + * toc table of contents + + * toc (table of contents) gives seek points + * for random access + * the ith entry determines the seek point for + * i-percent duration + * seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes + * e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes + */ + + +#define FRAMES_FLAG 0x0001 +#define BYTES_FLAG 0x0002 +#define TOC_FLAG 0x0004 +#define VBR_SCALE_FLAG 0x0008 + +#define NUMTOCENTRIES 100 + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined +struct lame_internal_flags; +typedef struct lame_internal_flags lame_internal_flags; +#endif + + +/*structure to receive extracted header */ +/* toc may be NULL*/ +typedef struct { + int h_id; /* from MPEG header, 0=MPEG2, 1=MPEG1 */ + int samprate; /* determined from MPEG header */ + int flags; /* from Vbr header data */ + int frames; /* total bit stream frames from Vbr header data */ + int bytes; /* total bit stream bytes from Vbr header data */ + int vbr_scale; /* encoded vbr scale from Vbr header data */ + unsigned char toc[NUMTOCENTRIES]; /* may be NULL if toc not desired */ + int headersize; /* size of VBR header, in bytes */ + int enc_delay; /* encoder delay */ + int enc_padding; /* encoder paddign added at end of stream */ +} VBRTAGDATA; + +int GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf); + +int InitVbrTag(lame_global_flags * gfp); +int PutVbrTag(lame_global_flags const *gfp, FILE * fid); +void AddVbrFrame(lame_internal_flags * gfc); +void UpdateMusicCRC(uint16_t * crc, const unsigned char *buffer, int size); + +#endif diff --git a/pkg/lame/clame/bitstream.c b/pkg/lame/clame/bitstream.c new file mode 100644 index 0000000..aa35915 --- /dev/null +++ b/pkg/lame/clame/bitstream.c @@ -0,0 +1,1111 @@ +/* + * MP3 bitstream Output interface for LAME + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 1999-2002 Takehiro Tominaga + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * $Id: bitstream.c,v 1.99 2017/08/31 14:14:46 robert Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "tables.h" +#include "quantize_pvt.h" +#include "lame_global_flags.h" +#include "gain_analysis.h" +#include "VbrTag.h" +#include "bitstream.h" +#include "tables.h" + + + +/* unsigned int is at least this large: */ +/* we work with ints, so when doing bit manipulation, we limit + * ourselves to MAX_LENGTH-2 just to be on the safe side */ +#define MAX_LENGTH 32 + + + +#ifdef DEBUG +static int hogege; +#endif + + + +static int +calcFrameLength(SessionConfig_t const *const cfg, int kbps, int pad) +{ + return 8 * ((cfg->version + 1) * 72000 * kbps / cfg->samplerate_out + pad); +} + + +/*********************************************************************** + * compute bitsperframe and mean_bits for a layer III frame + **********************************************************************/ +int +getframebits(const lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int bit_rate; + + /* get bitrate in kbps [?] */ + if (eov->bitrate_index) + bit_rate = bitrate_table[cfg->version][eov->bitrate_index]; + else + bit_rate = cfg->avg_bitrate; + /*assert(bit_rate <= 550); */ + assert(8 <= bit_rate && bit_rate <= 640); + + /* main encoding routine toggles padding on and off */ + /* one Layer3 Slot consists of 8 bits */ + return calcFrameLength(cfg, bit_rate, eov->padding); +} + +int +get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint) +{ + int maxmp3buf = 0; + if (cfg->avg_bitrate > 320) { + /* in freeformat the buffer is constant */ + if (constraint == MDB_STRICT_ISO) { + maxmp3buf = calcFrameLength(cfg, cfg->avg_bitrate, 0); + } + else { + /* maximum allowed bits per granule are 7680 */ + maxmp3buf = 7680 * (cfg->version + 1); + } + } + else { + int max_kbps; + if (cfg->samplerate_out < 16000) { + max_kbps = bitrate_table[cfg->version][8]; /* default: allow 64 kbps (MPEG-2.5) */ + } + else { + max_kbps = bitrate_table[cfg->version][14]; + } + switch (constraint) + { + default: + case MDB_DEFAULT: + /* Bouvigne suggests this more lax interpretation of the ISO doc instead of using 8*960. */ + /* All mp3 decoders should have enough buffer to handle this value: size of a 320kbps 32kHz frame */ + maxmp3buf = 8 * 1440; + break; + case MDB_STRICT_ISO: + maxmp3buf = calcFrameLength(cfg, max_kbps, 0); + break; + case MDB_MAXIMUM: + maxmp3buf = 7680 * (cfg->version + 1); + break; + } + } + return maxmp3buf; +} + + +static void +putheader_bits(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + Bit_stream_struc *bs = &gfc->bs; +#ifdef DEBUG + hogege += cfg->sideinfo_len * 8; +#endif + memcpy(&bs->buf[bs->buf_byte_idx], esv->header[esv->w_ptr].buf, cfg->sideinfo_len); + bs->buf_byte_idx += cfg->sideinfo_len; + bs->totbit += cfg->sideinfo_len * 8; + esv->w_ptr = (esv->w_ptr + 1) & (MAX_HEADER_BUF - 1); +} + + + + +/*write j bits into the bit stream */ +inline static void +putbits2(lame_internal_flags * gfc, int val, int j) +{ + EncStateVar_t const *const esv = &gfc->sv_enc; + Bit_stream_struc *bs; + bs = &gfc->bs; + + assert(j < MAX_LENGTH - 2); + + while (j > 0) { + int k; + if (bs->buf_bit_idx == 0) { + bs->buf_bit_idx = 8; + bs->buf_byte_idx++; + assert(bs->buf_byte_idx < BUFFER_SIZE); + assert(esv->header[esv->w_ptr].write_timing >= bs->totbit); + if (esv->header[esv->w_ptr].write_timing == bs->totbit) { + putheader_bits(gfc); + } + bs->buf[bs->buf_byte_idx] = 0; + } + + k = Min(j, bs->buf_bit_idx); + j -= k; + + bs->buf_bit_idx -= k; + + assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */ + assert(bs->buf_bit_idx < MAX_LENGTH); + + bs->buf[bs->buf_byte_idx] |= ((val >> j) << bs->buf_bit_idx); + bs->totbit += k; + } +} + +/*write j bits into the bit stream, ignoring frame headers */ +inline static void +putbits_noheaders(lame_internal_flags * gfc, int val, int j) +{ + Bit_stream_struc *bs; + bs = &gfc->bs; + + assert(j < MAX_LENGTH - 2); + + while (j > 0) { + int k; + if (bs->buf_bit_idx == 0) { + bs->buf_bit_idx = 8; + bs->buf_byte_idx++; + assert(bs->buf_byte_idx < BUFFER_SIZE); + bs->buf[bs->buf_byte_idx] = 0; + } + + k = Min(j, bs->buf_bit_idx); + j -= k; + + bs->buf_bit_idx -= k; + + assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */ + assert(bs->buf_bit_idx < MAX_LENGTH); + + bs->buf[bs->buf_byte_idx] |= ((val >> j) << bs->buf_bit_idx); + bs->totbit += k; + } +} + + +/* + Some combinations of bitrate, Fs, and stereo make it impossible to stuff + out a frame using just main_data, due to the limited number of bits to + indicate main_data_length. In these situations, we put stuffing bits into + the ancillary data... +*/ + +inline static void +drain_into_ancillary(lame_internal_flags * gfc, int remainingBits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int i; + assert(remainingBits >= 0); + + if (remainingBits >= 8) { + putbits2(gfc, 0x4c, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x41, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x4d, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x45, 8); + remainingBits -= 8; + } + + if (remainingBits >= 32) { + const char *const version = get_lame_short_version(); + if (remainingBits >= 32) + for (i = 0; i < (int) strlen(version) && remainingBits >= 8; ++i) { + remainingBits -= 8; + putbits2(gfc, version[i], 8); + } + } + + for (; remainingBits >= 1; remainingBits -= 1) { + putbits2(gfc, esv->ancillary_flag, 1); + esv->ancillary_flag ^= !cfg->disable_reservoir; + } + + assert(remainingBits == 0); + +} + +/*write N bits into the header */ +inline static void +writeheader(lame_internal_flags * gfc, int val, int j) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + int ptr = esv->header[esv->h_ptr].ptr; + + while (j > 0) { + int const k = Min(j, 8 - (ptr & 7)); + j -= k; + assert(j < MAX_LENGTH); /* >> 32 too large for 32 bit machines */ + esv->header[esv->h_ptr].buf[ptr >> 3] + |= ((val >> j)) << (8 - (ptr & 7) - k); + ptr += k; + } + esv->header[esv->h_ptr].ptr = ptr; +} + + +static int +CRC_update(int value, int crc) +{ + int i; + value <<= 8; + for (i = 0; i < 8; i++) { + value <<= 1; + crc <<= 1; + + if (((crc ^ value) & 0x10000)) + crc ^= CRC16_POLYNOMIAL; + } + return crc; +} + + +void +CRC_writeheader(lame_internal_flags const *gfc, char *header) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int crc = 0xffff; /* (jo) init crc16 for error_protection */ + int i; + + crc = CRC_update(((unsigned char *) header)[2], crc); + crc = CRC_update(((unsigned char *) header)[3], crc); + for (i = 6; i < cfg->sideinfo_len; i++) { + crc = CRC_update(((unsigned char *) header)[i], crc); + } + + header[4] = crc >> 8; + header[5] = crc & 255; +} + +inline static void +encodeSideInfo2(lame_internal_flags * gfc, int bitsPerFrame) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + EncStateVar_t *const esv = &gfc->sv_enc; + III_side_info_t *l3_side; + int gr, ch; + + l3_side = &gfc->l3_side; + esv->header[esv->h_ptr].ptr = 0; + memset(esv->header[esv->h_ptr].buf, 0, cfg->sideinfo_len); + if (cfg->samplerate_out < 16000) + writeheader(gfc, 0xffe, 12); + else + writeheader(gfc, 0xfff, 12); + writeheader(gfc, (cfg->version), 1); + writeheader(gfc, 4 - 3, 2); + writeheader(gfc, (!cfg->error_protection), 1); + writeheader(gfc, (eov->bitrate_index), 4); + writeheader(gfc, (cfg->samplerate_index), 2); + writeheader(gfc, (eov->padding), 1); + writeheader(gfc, (cfg->extension), 1); + writeheader(gfc, (cfg->mode), 2); + writeheader(gfc, (eov->mode_ext), 2); + writeheader(gfc, (cfg->copyright), 1); + writeheader(gfc, (cfg->original), 1); + writeheader(gfc, (cfg->emphasis), 2); + if (cfg->error_protection) { + writeheader(gfc, 0, 16); /* dummy */ + } + + if (cfg->version == 1) { + /* MPEG1 */ + assert(l3_side->main_data_begin >= 0); + writeheader(gfc, (l3_side->main_data_begin), 9); + + if (cfg->channels_out == 2) + writeheader(gfc, l3_side->private_bits, 3); + else + writeheader(gfc, l3_side->private_bits, 5); + + for (ch = 0; ch < cfg->channels_out; ch++) { + int band; + for (band = 0; band < 4; band++) { + writeheader(gfc, l3_side->scfsi[ch][band], 1); + } + } + + for (gr = 0; gr < 2; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const gi = &l3_side->tt[gr][ch]; + writeheader(gfc, gi->part2_3_length + gi->part2_length, 12); + writeheader(gfc, gi->big_values / 2, 9); + writeheader(gfc, gi->global_gain, 8); + writeheader(gfc, gi->scalefac_compress, 4); + + if (gi->block_type != NORM_TYPE) { + writeheader(gfc, 1, 1); /* window_switching_flag */ + writeheader(gfc, gi->block_type, 2); + writeheader(gfc, gi->mixed_block_flag, 1); + + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + + writeheader(gfc, gi->subblock_gain[0], 3); + writeheader(gfc, gi->subblock_gain[1], 3); + writeheader(gfc, gi->subblock_gain[2], 3); + } + else { + writeheader(gfc, 0, 1); /* window_switching_flag */ + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + if (gi->table_select[2] == 14) + gi->table_select[2] = 16; + writeheader(gfc, gi->table_select[2], 5); + + assert(0 <= gi->region0_count && gi->region0_count < 16); + assert(0 <= gi->region1_count && gi->region1_count < 8); + writeheader(gfc, gi->region0_count, 4); + writeheader(gfc, gi->region1_count, 3); + } + writeheader(gfc, gi->preflag, 1); + writeheader(gfc, gi->scalefac_scale, 1); + writeheader(gfc, gi->count1table_select, 1); + } + } + } + else { + /* MPEG2 */ + assert(l3_side->main_data_begin >= 0); + writeheader(gfc, (l3_side->main_data_begin), 8); + writeheader(gfc, l3_side->private_bits, cfg->channels_out); + + gr = 0; + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const gi = &l3_side->tt[gr][ch]; + writeheader(gfc, gi->part2_3_length + gi->part2_length, 12); + writeheader(gfc, gi->big_values / 2, 9); + writeheader(gfc, gi->global_gain, 8); + writeheader(gfc, gi->scalefac_compress, 9); + + if (gi->block_type != NORM_TYPE) { + writeheader(gfc, 1, 1); /* window_switching_flag */ + writeheader(gfc, gi->block_type, 2); + writeheader(gfc, gi->mixed_block_flag, 1); + + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + + writeheader(gfc, gi->subblock_gain[0], 3); + writeheader(gfc, gi->subblock_gain[1], 3); + writeheader(gfc, gi->subblock_gain[2], 3); + } + else { + writeheader(gfc, 0, 1); /* window_switching_flag */ + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + if (gi->table_select[2] == 14) + gi->table_select[2] = 16; + writeheader(gfc, gi->table_select[2], 5); + + assert(0 <= gi->region0_count && gi->region0_count < 16); + assert(0 <= gi->region1_count && gi->region1_count < 8); + writeheader(gfc, gi->region0_count, 4); + writeheader(gfc, gi->region1_count, 3); + } + + writeheader(gfc, gi->scalefac_scale, 1); + writeheader(gfc, gi->count1table_select, 1); + } + } + + if (cfg->error_protection) { + /* (jo) error_protection: add crc16 information to header */ + CRC_writeheader(gfc, esv->header[esv->h_ptr].buf); + } + + { + int const old = esv->h_ptr; + assert(esv->header[old].ptr == cfg->sideinfo_len * 8); + + esv->h_ptr = (old + 1) & (MAX_HEADER_BUF - 1); + esv->header[esv->h_ptr].write_timing = esv->header[old].write_timing + bitsPerFrame; + + if (esv->h_ptr == esv->w_ptr) { + /* yikes! we are out of header buffer space */ + ERRORF(gfc, "Error: MAX_HEADER_BUF too small in bitstream.c \n"); + } + + } +} + + +inline static int +huffman_coder_count1(lame_internal_flags * gfc, gr_info const *gi) +{ + /* Write count1 area */ + struct huffcodetab const *const h = &ht[gi->count1table_select + 32]; + int i, bits = 0; +#ifdef DEBUG + int gegebo = gfc->bs.totbit; +#endif + + int const *ix = &gi->l3_enc[gi->big_values]; + FLOAT const *xr = &gi->xr[gi->big_values]; + assert(gi->count1table_select < 2); + + for (i = (gi->count1 - gi->big_values) / 4; i > 0; --i) { + int huffbits = 0; + int p = 0, v; + + v = ix[0]; + if (v) { + p += 8; + if (xr[0] < 0.0f) + huffbits++; + assert(v <= 1); + } + + v = ix[1]; + if (v) { + p += 4; + huffbits *= 2; + if (xr[1] < 0.0f) + huffbits++; + assert(v <= 1); + } + + v = ix[2]; + if (v) { + p += 2; + huffbits *= 2; + if (xr[2] < 0.0f) + huffbits++; + assert(v <= 1); + } + + v = ix[3]; + if (v) { + p++; + huffbits *= 2; + if (xr[3] < 0.0f) + huffbits++; + assert(v <= 1); + } + + ix += 4; + xr += 4; + putbits2(gfc, huffbits + h->table[p], h->hlen[p]); + bits += h->hlen[p]; + } +#ifdef DEBUG + DEBUGF(gfc, "count1: real: %ld counted:%d (bigv %d count1len %d)\n", + gfc->bs.totbit - gegebo, gi->count1bits, gi->big_values, gi->count1); +#endif + return bits; +} + + + +/* + Implements the pseudocode of page 98 of the IS + */ +inline static int +Huffmancode(lame_internal_flags * const gfc, const unsigned int tableindex, + int start, int end, gr_info const *gi) +{ + struct huffcodetab const *const h = &ht[tableindex]; + unsigned int const linbits = h->xlen; + int i, bits = 0; + + assert(tableindex < 32u); + if (!tableindex) + return bits; + + for (i = start; i < end; i += 2) { + int16_t cbits = 0; + uint16_t xbits = 0; + unsigned int xlen = h->xlen; + unsigned int ext = 0; + unsigned int x1 = gi->l3_enc[i]; + unsigned int x2 = gi->l3_enc[i + 1]; + + assert(gi->l3_enc[i] >= 0); + assert(gi->l3_enc[i+1] >= 0); + + if (x1 != 0u) { + if (gi->xr[i] < 0.0f) + ext++; + cbits--; + } + + if (tableindex > 15u) { + /* use ESC-words */ + if (x1 >= 15u) { + uint16_t const linbits_x1 = x1 - 15u; + assert(linbits_x1 <= h->linmax); + ext |= linbits_x1 << 1u; + xbits = linbits; + x1 = 15u; + } + + if (x2 >= 15u) { + uint16_t const linbits_x2 = x2 - 15u; + assert(linbits_x2 <= h->linmax); + ext <<= linbits; + ext |= linbits_x2; + xbits += linbits; + x2 = 15u; + } + xlen = 16; + } + + if (x2 != 0u) { + ext <<= 1; + if (gi->xr[i + 1] < 0.0f) + ext++; + cbits--; + } + + assert((x1 | x2) < 16u); + + x1 = x1 * xlen + x2; + xbits -= cbits; + cbits += h->hlen[x1]; + + assert(cbits <= MAX_LENGTH); + assert(xbits <= MAX_LENGTH); + + putbits2(gfc, h->table[x1], cbits); + putbits2(gfc, (int)ext, xbits); + bits += cbits + xbits; + } + return bits; +} + +/* + Note the discussion of huffmancodebits() on pages 28 + and 29 of the IS, as well as the definitions of the side + information on pages 26 and 27. + */ +static int +ShortHuffmancodebits(lame_internal_flags * gfc, gr_info const *gi) +{ + int bits; + int region1Start; + + region1Start = 3 * gfc->scalefac_band.s[3]; + if (region1Start > gi->big_values) + region1Start = gi->big_values; + + /* short blocks do not have a region2 */ + bits = Huffmancode(gfc, gi->table_select[0], 0, region1Start, gi); + bits += Huffmancode(gfc, gi->table_select[1], region1Start, gi->big_values, gi); + return bits; +} + +static int +LongHuffmancodebits(lame_internal_flags * gfc, gr_info const *gi) +{ + unsigned int i; + int bigvalues, bits; + int region1Start, region2Start; + + bigvalues = gi->big_values; + assert(0 <= bigvalues && bigvalues <= 576); + + assert(gi->region0_count >= -1); + assert(gi->region1_count >= -1); + i = gi->region0_count + 1; + assert((size_t) i < dimension_of(gfc->scalefac_band.l)); + region1Start = gfc->scalefac_band.l[i]; + i += gi->region1_count + 1; + assert((size_t) i < dimension_of(gfc->scalefac_band.l)); + region2Start = gfc->scalefac_band.l[i]; + + if (region1Start > bigvalues) + region1Start = bigvalues; + + if (region2Start > bigvalues) + region2Start = bigvalues; + + bits = Huffmancode(gfc, gi->table_select[0], 0, region1Start, gi); + bits += Huffmancode(gfc, gi->table_select[1], region1Start, region2Start, gi); + bits += Huffmancode(gfc, gi->table_select[2], region2Start, bigvalues, gi); + return bits; +} + +inline static int +writeMainData(lame_internal_flags * const gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + III_side_info_t const *const l3_side = &gfc->l3_side; + int gr, ch, sfb, data_bits, tot_bits = 0; + + if (cfg->version == 1) { + /* MPEG 1 */ + for (gr = 0; gr < 2; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const gi = &l3_side->tt[gr][ch]; + int const slen1 = slen1_tab[gi->scalefac_compress]; + int const slen2 = slen2_tab[gi->scalefac_compress]; + data_bits = 0; +#ifdef DEBUG + hogege = gfc->bs.totbit; +#endif + for (sfb = 0; sfb < gi->sfbdivide; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; /* scfsi is used */ + putbits2(gfc, gi->scalefac[sfb], slen1); + data_bits += slen1; + } + for (; sfb < gi->sfbmax; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; /* scfsi is used */ + putbits2(gfc, gi->scalefac[sfb], slen2); + data_bits += slen2; + } + assert(data_bits == gi->part2_length); + + if (gi->block_type == SHORT_TYPE) { + data_bits += ShortHuffmancodebits(gfc, gi); + } + else { + data_bits += LongHuffmancodebits(gfc, gi); + } + data_bits += huffman_coder_count1(gfc, gi); +#ifdef DEBUG + DEBUGF(gfc, "<%ld> ", gfc->bs.totbit - hogege); +#endif + /* does bitcount in quantize.c agree with actual bit count? */ + assert(data_bits == gi->part2_3_length + gi->part2_length); + tot_bits += data_bits; + } /* for ch */ + } /* for gr */ + } + else { + /* MPEG 2 */ + gr = 0; + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const gi = &l3_side->tt[gr][ch]; + int i, sfb_partition, scale_bits = 0; + assert(gi->sfb_partition_table); + data_bits = 0; +#ifdef DEBUG + hogege = gfc->bs.totbit; +#endif + sfb = 0; + sfb_partition = 0; + + if (gi->block_type == SHORT_TYPE) { + for (; sfb_partition < 4; sfb_partition++) { + int const sfbs = gi->sfb_partition_table[sfb_partition] / 3; + int const slen = gi->slen[sfb_partition]; + for (i = 0; i < sfbs; i++, sfb++) { + putbits2(gfc, Max(gi->scalefac[sfb * 3 + 0], 0), slen); + putbits2(gfc, Max(gi->scalefac[sfb * 3 + 1], 0), slen); + putbits2(gfc, Max(gi->scalefac[sfb * 3 + 2], 0), slen); + scale_bits += 3 * slen; + } + } + data_bits += ShortHuffmancodebits(gfc, gi); + } + else { + for (; sfb_partition < 4; sfb_partition++) { + int const sfbs = gi->sfb_partition_table[sfb_partition]; + int const slen = gi->slen[sfb_partition]; + for (i = 0; i < sfbs; i++, sfb++) { + putbits2(gfc, Max(gi->scalefac[sfb], 0), slen); + scale_bits += slen; + } + } + data_bits += LongHuffmancodebits(gfc, gi); + } + data_bits += huffman_coder_count1(gfc, gi); +#ifdef DEBUG + DEBUGF(gfc, "<%ld> ", gfc->bs.totbit - hogege); +#endif + /* does bitcount in quantize.c agree with actual bit count? */ + assert(data_bits == gi->part2_3_length); + assert(scale_bits == gi->part2_length); + tot_bits += scale_bits + data_bits; + } /* for ch */ + } /* for gf */ + return tot_bits; +} /* main_data */ + + + +/* compute the number of bits required to flush all mp3 frames + currently in the buffer. This should be the same as the + reservoir size. Only call this routine between frames - i.e. + only after all headers and data have been added to the buffer + by format_bitstream(). + + Also compute total_bits_output = + size of mp3 buffer (including frame headers which may not + have yet been send to the mp3 buffer) + + number of bits needed to flush all mp3 frames. + + total_bytes_output is the size of the mp3 output buffer if + lame_encode_flush_nogap() was called right now. + + */ +int +compute_flushbits(const lame_internal_flags * gfc, int *total_bytes_output) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t const *const esv = &gfc->sv_enc; + int flushbits, remaining_headers; + int bitsPerFrame; + int last_ptr, first_ptr; + first_ptr = esv->w_ptr; /* first header to add to bitstream */ + last_ptr = esv->h_ptr - 1; /* last header to add to bitstream */ + if (last_ptr == -1) + last_ptr = MAX_HEADER_BUF - 1; + + /* add this many bits to bitstream so we can flush all headers */ + flushbits = esv->header[last_ptr].write_timing - gfc->bs.totbit; + *total_bytes_output = flushbits; + + if (flushbits >= 0) { + /* if flushbits >= 0, some headers have not yet been written */ + /* reduce flushbits by the size of the headers */ + remaining_headers = 1 + last_ptr - first_ptr; + if (last_ptr < first_ptr) + remaining_headers = 1 + last_ptr - first_ptr + MAX_HEADER_BUF; + flushbits -= remaining_headers * 8 * cfg->sideinfo_len; + } + + + /* finally, add some bits so that the last frame is complete + * these bits are not necessary to decode the last frame, but + * some decoders will ignore last frame if these bits are missing + */ + bitsPerFrame = getframebits(gfc); + flushbits += bitsPerFrame; + *total_bytes_output += bitsPerFrame; + /* round up: */ + if (*total_bytes_output % 8) + *total_bytes_output = 1 + (*total_bytes_output / 8); + else + *total_bytes_output = (*total_bytes_output / 8); + *total_bytes_output += gfc->bs.buf_byte_idx + 1; + + + if (flushbits < 0) { +#if 0 + /* if flushbits < 0, this would mean that the buffer looks like: + * (data...) last_header (data...) (extra data that should not be here...) + */ + DEBUGF(gfc, "last header write_timing = %i \n", esv->header[last_ptr].write_timing); + DEBUGF(gfc, "first header write_timing = %i \n", esv->header[first_ptr].write_timing); + DEBUGF(gfc, "bs.totbit: %i \n", gfc->bs.totbit); + DEBUGF(gfc, "first_ptr, last_ptr %i %i \n", first_ptr, last_ptr); + DEBUGF(gfc, "remaining_headers = %i \n", remaining_headers); + DEBUGF(gfc, "bitsperframe: %i \n", bitsPerFrame); + DEBUGF(gfc, "sidelen: %i \n", cfg->sideinfo_len); +#endif + ERRORF(gfc, "strange error flushing buffer ... \n"); + } + return flushbits; +} + + +void +flush_bitstream(lame_internal_flags * gfc) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + III_side_info_t *l3_side; + int nbytes; + int flushbits; + int last_ptr = esv->h_ptr - 1; /* last header to add to bitstream */ + if (last_ptr == -1) + last_ptr = MAX_HEADER_BUF - 1; + l3_side = &gfc->l3_side; + + + if ((flushbits = compute_flushbits(gfc, &nbytes)) < 0) + return; + drain_into_ancillary(gfc, flushbits); + + /* check that the 100% of the last frame has been written to bitstream */ + assert(esv->header[last_ptr].write_timing + getframebits(gfc) + == gfc->bs.totbit); + + /* we have padded out all frames with ancillary data, which is the + same as filling the bitreservoir with ancillary data, so : */ + esv->ResvSize = 0; + l3_side->main_data_begin = 0; +} + + + + +void +add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + int i; + + while (n-- > 0u) { + putbits_noheaders(gfc, val, 8); + + for (i = 0; i < MAX_HEADER_BUF; ++i) + esv->header[i].write_timing += 8; + } +} + + +/* + format_bitstream() + + This is called after a frame of audio has been quantized and coded. + It will write the encoded audio to the bitstream. Note that + from a layer3 encoder's perspective the bit stream is primarily + a series of main_data() blocks, with header and side information + inserted at the proper locations to maintain framing. (See Figure A.7 + in the IS). + */ +int +format_bitstream(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int bits, nbytes; + III_side_info_t *l3_side; + int bitsPerFrame; + l3_side = &gfc->l3_side; + + bitsPerFrame = getframebits(gfc); + drain_into_ancillary(gfc, l3_side->resvDrain_pre); + + encodeSideInfo2(gfc, bitsPerFrame); + bits = 8 * cfg->sideinfo_len; + bits += writeMainData(gfc); + drain_into_ancillary(gfc, l3_side->resvDrain_post); + bits += l3_side->resvDrain_post; + + l3_side->main_data_begin += (bitsPerFrame - bits) / 8; + + /* compare number of bits needed to clear all buffered mp3 frames + * with what we think the resvsize is: */ + if (compute_flushbits(gfc, &nbytes) != esv->ResvSize) { + ERRORF(gfc, "Internal buffer inconsistency. flushbits <> ResvSize"); + } + + + /* compare main_data_begin for the next frame with what we + * think the resvsize is: */ + if ((l3_side->main_data_begin * 8) != esv->ResvSize) { + ERRORF(gfc, "bit reservoir error: \n" + "l3_side->main_data_begin: %i \n" + "Resvoir size: %i \n" + "resv drain (post) %i \n" + "resv drain (pre) %i \n" + "header and sideinfo: %i \n" + "data bits: %i \n" + "total bits: %i (remainder: %i) \n" + "bitsperframe: %i \n", + 8 * l3_side->main_data_begin, + esv->ResvSize, + l3_side->resvDrain_post, + l3_side->resvDrain_pre, + 8 * cfg->sideinfo_len, + bits - l3_side->resvDrain_post - 8 * cfg->sideinfo_len, + bits, bits % 8, bitsPerFrame); + + ERRORF(gfc, "This is a fatal error. It has several possible causes:"); + ERRORF(gfc, "90%% LAME compiled with buggy version of gcc using advanced optimizations"); + ERRORF(gfc, " 9%% Your system is overclocked"); + ERRORF(gfc, " 1%% bug in LAME encoding library"); + + esv->ResvSize = l3_side->main_data_begin * 8; + }; + assert(gfc->bs.totbit % 8 == 0); + + if (gfc->bs.totbit > 1000000000) { + /* to avoid totbit overflow, (at 8h encoding at 128kbs) lets reset bit counter */ + int i; + for (i = 0; i < MAX_HEADER_BUF; ++i) + esv->header[i].write_timing -= gfc->bs.totbit; + gfc->bs.totbit = 0; + } + + + return 0; +} + + +static int +do_gain_analysis(lame_internal_flags * gfc, unsigned char* buffer, int minimum) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + RpgStateVar_t const *const rsv = &gfc->sv_rpg; + RpgResult_t *const rov = &gfc->ov_rpg; +#ifdef DECODE_ON_THE_FLY + if (cfg->decode_on_the_fly) { /* decode the frame */ + sample_t pcm_buf[2][1152]; + int mp3_in = minimum; + int samples_out = -1; + + /* re-synthesis to pcm. Repeat until we get a samples_out=0 */ + while (samples_out != 0) { + + samples_out = hip_decode1_unclipped(gfc->hip, buffer, mp3_in, pcm_buf[0], pcm_buf[1]); + /* samples_out = 0: need more data to decode + * samples_out = -1: error. Lets assume 0 pcm output + * samples_out = number of samples output */ + + /* set the lenght of the mp3 input buffer to zero, so that in the + * next iteration of the loop we will be querying mpglib about + * buffered data */ + mp3_in = 0; + + if (samples_out == -1) { + /* error decoding. Not fatal, but might screw up + * the ReplayGain tag. What should we do? Ignore for now */ + samples_out = 0; + } + if (samples_out > 0) { + /* process the PCM data */ + + /* this should not be possible, and indicates we have + * overflown the pcm_buf buffer */ + assert(samples_out <= 1152); + + if (cfg->findPeakSample) { + int i; + /* FIXME: is this correct? maybe Max(fabs(pcm),PeakSample) */ + for (i = 0; i < samples_out; i++) { + if (pcm_buf[0][i] > rov->PeakSample) + rov->PeakSample = pcm_buf[0][i]; + else if (-pcm_buf[0][i] > rov->PeakSample) + rov->PeakSample = -pcm_buf[0][i]; + } + if (cfg->channels_out > 1) + for (i = 0; i < samples_out; i++) { + if (pcm_buf[1][i] > rov->PeakSample) + rov->PeakSample = pcm_buf[1][i]; + else if (-pcm_buf[1][i] > rov->PeakSample) + rov->PeakSample = -pcm_buf[1][i]; + } + } + + if (cfg->findReplayGain) + if (AnalyzeSamples + (rsv->rgdata, pcm_buf[0], pcm_buf[1], samples_out, + cfg->channels_out) == GAIN_ANALYSIS_ERROR) + return -6; + + } /* if (samples_out>0) */ + } /* while (samples_out!=0) */ + } /* if (gfc->decode_on_the_fly) */ +#endif + return minimum; +} + +static int +do_copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int size) +{ + Bit_stream_struc *const bs = &gfc->bs; + int const minimum = bs->buf_byte_idx + 1; + if (minimum <= 0) + return 0; + if (minimum > size) + return -1; /* buffer is too small */ + memcpy(buffer, bs->buf, minimum); + bs->buf_byte_idx = -1; + bs->buf_bit_idx = 0; + return minimum; +} + +/* copy data out of the internal MP3 bit buffer into a user supplied + unsigned char buffer. + + mp3data=0 indicates data in buffer is an id3tags and VBR tags + mp3data=1 data is real mp3 frame data. + + +*/ +int +copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int size, int mp3data) +{ + int const minimum = do_copy_buffer(gfc, buffer, size); + if (minimum > 0 && mp3data) { + UpdateMusicCRC(&gfc->nMusicCRC, buffer, minimum); + + /** sum number of bytes belonging to the mp3 stream + * this info will be written into the Xing/LAME header for seeking + */ + gfc->VBR_seek_table.nBytesWritten += minimum; + + return do_gain_analysis(gfc, buffer, minimum); + } /* if (mp3data) */ + return minimum; +} + + +void +init_bit_stream_w(lame_internal_flags * gfc) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + + esv->h_ptr = esv->w_ptr = 0; + esv->header[esv->h_ptr].write_timing = 0; + + gfc->bs.buf = lame_calloc(unsigned char, BUFFER_SIZE); + gfc->bs.buf_size = BUFFER_SIZE; + gfc->bs.buf_byte_idx = -1; + gfc->bs.buf_bit_idx = 0; + gfc->bs.totbit = 0; +} + +/* end of bitstream.c */ diff --git a/pkg/lame/clame/bitstream.h b/pkg/lame/clame/bitstream.h new file mode 100644 index 0000000..3ae48d0 --- /dev/null +++ b/pkg/lame/clame/bitstream.h @@ -0,0 +1,40 @@ +/* + * MP3 bitstream Output interface for LAME + * + * Copyright (c) 1999 Takehiro TOMINAGA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_BITSTREAM_H +#define LAME_BITSTREAM_H + +int getframebits(const lame_internal_flags * gfc); + +int format_bitstream(lame_internal_flags * gfc); + +void flush_bitstream(lame_internal_flags * gfc); +void add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n); + +int copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int buffer_size, + int update_crc); +void init_bit_stream_w(lame_internal_flags * gfc); +void CRC_writeheader(lame_internal_flags const *gfc, char *buffer); +int compute_flushbits(const lame_internal_flags * gfp, int *nbytes); + +int get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint); + +#endif diff --git a/pkg/lame/clame/config.h b/pkg/lame/clame/config.h new file mode 100644 index 0000000..4df73ee --- /dev/null +++ b/pkg/lame/clame/config.h @@ -0,0 +1,30 @@ +#ifndef LAME_CONFIG_H +#define LAME_CONFIG_H + +#define STDC_HEADERS + +/* +#define __int8_t_defined +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#define uint64_t unsigned long long + +#define int8_t signed char +#define int16_t signed short +#define int32_t signed int +#define int64_t signed long long +*/ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +typedef long double ieee854_float80_t; +typedef double ieee754_float64_t; +typedef float ieee754_float32_t; +#endif /* LAME_CONFIG_H */ diff --git a/pkg/lame/clame/encoder.c b/pkg/lame/clame/encoder.c new file mode 100644 index 0000000..48f46c7 --- /dev/null +++ b/pkg/lame/clame/encoder.c @@ -0,0 +1,574 @@ +/* + * LAME MP3 encoding engine + * + * Copyright (c) 1999 Mark Taylor + * Copyright (c) 2000-2002 Takehiro Tominaga + * Copyright (c) 2000-2011 Robert Hegemann + * Copyright (c) 2001 Gabriel Bouvigne + * Copyright (c) 2001 John Dahlstrom + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: encoder.c,v 1.114 2017/08/26 10:54:57 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "lame_global_flags.h" +#include "newmdct.h" +#include "psymodel.h" +#include "lame-analysis.h" +#include "bitstream.h" +#include "VbrTag.h" +#include "quantize.h" +#include "quantize_pvt.h" + + + +/* + * auto-adjust of ATH, useful for low volume + * Gabriel Bouvigne 3 feb 2001 + * + * modifies some values in + * gfp->internal_flags->ATH + * (gfc->ATH) + */ +static void +adjust_ATH(lame_internal_flags const *const gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + FLOAT gr2_max, max_pow; + + if (gfc->ATH->use_adjust == 0) { + gfc->ATH->adjust_factor = 1.0; /* no adjustment */ + return; + } + + /* jd - 2001 mar 12, 27, jun 30 */ + /* loudness based on equal loudness curve; */ + /* use granule with maximum combined loudness */ + max_pow = gfc->ov_psy.loudness_sq[0][0]; + gr2_max = gfc->ov_psy.loudness_sq[1][0]; + if (cfg->channels_out == 2) { + max_pow += gfc->ov_psy.loudness_sq[0][1]; + gr2_max += gfc->ov_psy.loudness_sq[1][1]; + } + else { + max_pow += max_pow; + gr2_max += gr2_max; + } + if (cfg->mode_gr == 2) { + max_pow = Max(max_pow, gr2_max); + } + max_pow *= 0.5; /* max_pow approaches 1.0 for full band noise */ + + /* jd - 2001 mar 31, jun 30 */ + /* user tuning of ATH adjustment region */ + max_pow *= gfc->ATH->aa_sensitivity_p; + + /* adjust ATH depending on range of maximum value + */ + + /* jd - 2001 feb27, mar12,20, jun30, jul22 */ + /* continuous curves based on approximation */ + /* to GB's original values. */ + /* For an increase in approximate loudness, */ + /* set ATH adjust to adjust_limit immediately */ + /* after a delay of one frame. */ + /* For a loudness decrease, reduce ATH adjust */ + /* towards adjust_limit gradually. */ + /* max_pow is a loudness squared or a power. */ + if (max_pow > 0.03125) { /* ((1 - 0.000625)/ 31.98) from curve below */ + if (gfc->ATH->adjust_factor >= 1.0) { + gfc->ATH->adjust_factor = 1.0; + } + else { + /* preceding frame has lower ATH adjust; */ + /* ascend only to the preceding adjust_limit */ + /* in case there is leading low volume */ + if (gfc->ATH->adjust_factor < gfc->ATH->adjust_limit) { + gfc->ATH->adjust_factor = gfc->ATH->adjust_limit; + } + } + gfc->ATH->adjust_limit = 1.0; + } + else { /* adjustment curve */ + /* about 32 dB maximum adjust (0.000625) */ + FLOAT const adj_lim_new = 31.98 * max_pow + 0.000625; + if (gfc->ATH->adjust_factor >= adj_lim_new) { /* descend gradually */ + gfc->ATH->adjust_factor *= adj_lim_new * 0.075 + 0.925; + if (gfc->ATH->adjust_factor < adj_lim_new) { /* stop descent */ + gfc->ATH->adjust_factor = adj_lim_new; + } + } + else { /* ascend */ + if (gfc->ATH->adjust_limit >= adj_lim_new) { + gfc->ATH->adjust_factor = adj_lim_new; + } + else { /* preceding frame has lower ATH adjust; */ + /* ascend only to the preceding adjust_limit */ + if (gfc->ATH->adjust_factor < gfc->ATH->adjust_limit) { + gfc->ATH->adjust_factor = gfc->ATH->adjust_limit; + } + } + } + gfc->ATH->adjust_limit = adj_lim_new; + } +} + +/*********************************************************************** + * + * some simple statistics + * + * bitrate index 0: free bitrate -> not allowed in VBR mode + * : bitrates, kbps depending on MPEG version + * bitrate index 15: forbidden + * + * mode_ext: + * 0: LR + * 1: LR-i + * 2: MS + * 3: MS-i + * + ***********************************************************************/ + +static void +updateStats(lame_internal_flags * const gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *eov = &gfc->ov_enc; + int gr, ch; + assert(0 <= eov->bitrate_index && eov->bitrate_index < 16); + assert(0 <= eov->mode_ext && eov->mode_ext < 4); + + /* count bitrate indices */ + eov->bitrate_channelmode_hist[eov->bitrate_index][4]++; + eov->bitrate_channelmode_hist[15][4]++; + + /* count 'em for every mode extension in case of 2 channel encoding */ + if (cfg->channels_out == 2) { + eov->bitrate_channelmode_hist[eov->bitrate_index][eov->mode_ext]++; + eov->bitrate_channelmode_hist[15][eov->mode_ext]++; + } + for (gr = 0; gr < cfg->mode_gr; ++gr) { + for (ch = 0; ch < cfg->channels_out; ++ch) { + int bt = gfc->l3_side.tt[gr][ch].block_type; + if (gfc->l3_side.tt[gr][ch].mixed_block_flag) + bt = 4; + eov->bitrate_blocktype_hist[eov->bitrate_index][bt]++; + eov->bitrate_blocktype_hist[eov->bitrate_index][5]++; + eov->bitrate_blocktype_hist[15][bt]++; + eov->bitrate_blocktype_hist[15][5]++; + } + } +} + + + + +static void +lame_encode_frame_init(lame_internal_flags * gfc, const sample_t *const inbuf[2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + + int ch, gr; + + if (gfc->lame_encode_frame_init == 0) { + sample_t primebuff0[286 + 1152 + 576]; + sample_t primebuff1[286 + 1152 + 576]; + int const framesize = 576 * cfg->mode_gr; + /* prime the MDCT/polyphase filterbank with a short block */ + int i, j; + gfc->lame_encode_frame_init = 1; + memset(primebuff0, 0, sizeof(primebuff0)); + memset(primebuff1, 0, sizeof(primebuff1)); + for (i = 0, j = 0; i < 286 + 576 * (1 + cfg->mode_gr); ++i) { + if (i < framesize) { + primebuff0[i] = 0; + if (cfg->channels_out == 2) + primebuff1[i] = 0; + } + else { + primebuff0[i] = inbuf[0][j]; + if (cfg->channels_out == 2) + primebuff1[i] = inbuf[1][j]; + ++j; + } + } + /* polyphase filtering / mdct */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gfc->l3_side.tt[gr][ch].block_type = SHORT_TYPE; + } + } + mdct_sub48(gfc, primebuff0, primebuff1); + + /* check FFT will not use a negative starting offset */ +#if 576 < FFTOFFSET +# error FFTOFFSET greater than 576: FFT uses a negative offset +#endif + /* check if we have enough data for FFT */ + assert(gfc->sv_enc.mf_size >= (BLKSIZE + framesize - FFTOFFSET)); + /* check if we have enough data for polyphase filterbank */ + assert(gfc->sv_enc.mf_size >= (512 + framesize - 32)); + } + +} + + + + + + + +/************************************************************************ +* +* encodeframe() Layer 3 +* +* encode a single frame +* +************************************************************************ +lame_encode_frame() + + + gr 0 gr 1 +inbuf: |--------------|--------------|--------------| + + +Polyphase (18 windows, each shifted 32) +gr 0: +window1 <----512----> +window18 <----512----> + +gr 1: +window1 <----512----> +window18 <----512----> + + + +MDCT output: |--------------|--------------|--------------| + +FFT's <---------1024----------> + <---------1024--------> + + + + inbuf = buffer of PCM data size=MP3 framesize + encoder acts on inbuf[ch][0], but output is delayed by MDCTDELAY + so the MDCT coefficints are from inbuf[ch][-MDCTDELAY] + + psy-model FFT has a 1 granule delay, so we feed it data for the + next granule. + FFT is centered over granule: 224+576+224 + So FFT starts at: 576-224-MDCTDELAY + + MPEG2: FFT ends at: BLKSIZE+576-224-MDCTDELAY (1328) + MPEG1: FFT ends at: BLKSIZE+2*576-224-MDCTDELAY (1904) + + MPEG2: polyphase first window: [0..511] + 18th window: [544..1055] (1056) + MPEG1: 36th window: [1120..1631] (1632) + data needed: 512+framesize-32 + + A close look newmdct.c shows that the polyphase filterbank + only uses data from [0..510] for each window. Perhaps because the window + used by the filterbank is zero for the last point, so Takehiro's + code doesn't bother to compute with it. + + FFT starts at 576-224-MDCTDELAY (304) = 576-FFTOFFSET + +*/ + +typedef FLOAT chgrdata[2][2]; + + +int +lame_encode_mp3_frame( /* Output */ + lame_internal_flags * gfc, /* Context */ + sample_t const *inbuf_l, /* Input */ + sample_t const *inbuf_r, /* Input */ + unsigned char *mp3buf, /* Output */ + int mp3buf_size) +{ /* Output */ + SessionConfig_t const *const cfg = &gfc->cfg; + int mp3count; + III_psy_ratio masking_LR[2][2]; /*LR masking & energy */ + III_psy_ratio masking_MS[2][2]; /*MS masking & energy */ + const III_psy_ratio (*masking)[2]; /*pointer to selected maskings */ + const sample_t *inbuf[2]; + + FLOAT tot_ener[2][4]; + FLOAT ms_ener_ratio[2] = { .5, .5 }; + FLOAT pe[2][2] = { {0., 0.}, {0., 0.} }, pe_MS[2][2] = { { + 0., 0.}, { + 0., 0.}}; + FLOAT (*pe_use)[2]; + + int ch, gr; + + inbuf[0] = inbuf_l; + inbuf[1] = inbuf_r; + + if (gfc->lame_encode_frame_init == 0) { + /*first run? */ + lame_encode_frame_init(gfc, inbuf); + + } + + + /********************** padding *****************************/ + /* padding method as described in + * "MPEG-Layer3 / Bitstream Syntax and Decoding" + * by Martin Sieler, Ralph Sperschneider + * + * note: there is no padding for the very first frame + * + * Robert Hegemann 2000-06-22 + */ + gfc->ov_enc.padding = FALSE; + if ((gfc->sv_enc.slot_lag -= gfc->sv_enc.frac_SpF) < 0) { + gfc->sv_enc.slot_lag += cfg->samplerate_out; + gfc->ov_enc.padding = TRUE; + } + + + + /**************************************** + * Stage 1: psychoacoustic model * + ****************************************/ + + { + /* psychoacoustic model + * psy model has a 1 granule (576) delay that we must compensate for + * (mt 6/99). + */ + int ret; + const sample_t *bufp[2] = {0, 0}; /* address of beginning of left & right granule */ + int blocktype[2]; + + for (gr = 0; gr < cfg->mode_gr; gr++) { + + for (ch = 0; ch < cfg->channels_out; ch++) { + bufp[ch] = &inbuf[ch][576 + gr * 576 - FFTOFFSET]; + } + ret = L3psycho_anal_vbr(gfc, bufp, gr, + masking_LR, masking_MS, + pe[gr], pe_MS[gr], tot_ener[gr], blocktype); + if (ret != 0) + return -4; + + if (cfg->mode == JOINT_STEREO) { + ms_ener_ratio[gr] = tot_ener[gr][2] + tot_ener[gr][3]; + if (ms_ener_ratio[gr] > 0) + ms_ener_ratio[gr] = tot_ener[gr][3] / ms_ener_ratio[gr]; + } + + /* block type flags */ + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + cod_info->block_type = blocktype[ch]; + cod_info->mixed_block_flag = 0; + } + } + } + + + /* auto-adjust of ATH, useful for low volume */ + adjust_ATH(gfc); + + + /**************************************** + * Stage 2: MDCT * + ****************************************/ + + /* polyphase filtering / mdct */ + mdct_sub48(gfc, inbuf[0], inbuf[1]); + + + /**************************************** + * Stage 3: MS/LR decision * + ****************************************/ + + /* Here will be selected MS or LR coding of the 2 stereo channels */ + gfc->ov_enc.mode_ext = MPG_MD_LR_LR; + + if (cfg->force_ms) { + gfc->ov_enc.mode_ext = MPG_MD_MS_LR; + } + else if (cfg->mode == JOINT_STEREO) { + /* ms_ratio = is scaled, for historical reasons, to look like + a ratio of side_channel / total. + 0 = signal is 100% mono + .5 = L & R uncorrelated + */ + + /* [0] and [1] are the results for the two granules in MPEG-1, + * in MPEG-2 it's only a faked averaging of the same value + * _prev is the value of the last granule of the previous frame + * _next is the value of the first granule of the next frame + */ + + FLOAT sum_pe_MS = 0; + FLOAT sum_pe_LR = 0; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + sum_pe_MS += pe_MS[gr][ch]; + sum_pe_LR += pe[gr][ch]; + } + } + + /* based on PE: M/S coding would not use much more bits than L/R */ + if (sum_pe_MS <= 1.00 * sum_pe_LR) { + + gr_info const *const gi0 = &gfc->l3_side.tt[0][0]; + gr_info const *const gi1 = &gfc->l3_side.tt[cfg->mode_gr - 1][0]; + + if (gi0[0].block_type == gi0[1].block_type && gi1[0].block_type == gi1[1].block_type) { + + gfc->ov_enc.mode_ext = MPG_MD_MS_LR; + } + } + } + + /* bit and noise allocation */ + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + masking = (const III_psy_ratio (*)[2])masking_MS; /* use MS masking */ + pe_use = pe_MS; + } + else { + masking = (const III_psy_ratio (*)[2])masking_LR; /* use LR masking */ + pe_use = pe; + } + + + /* copy data for MP3 frame analyzer */ + if (cfg->analysis && gfc->pinfo != NULL) { + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gfc->pinfo->ms_ratio[gr] = 0; + gfc->pinfo->ms_ener_ratio[gr] = ms_ener_ratio[gr]; + gfc->pinfo->blocktype[gr][ch] = gfc->l3_side.tt[gr][ch].block_type; + gfc->pinfo->pe[gr][ch] = pe_use[gr][ch]; + memcpy(gfc->pinfo->xr[gr][ch], &gfc->l3_side.tt[gr][ch].xr[0], sizeof(FLOAT) * 576); + /* in psymodel, LR and MS data was stored in pinfo. + switch to MS data: */ + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + gfc->pinfo->ers[gr][ch] = gfc->pinfo->ers[gr][ch + 2]; + memcpy(gfc->pinfo->energy[gr][ch], gfc->pinfo->energy[gr][ch + 2], + sizeof(gfc->pinfo->energy[gr][ch])); + } + } + } + } + + + /**************************************** + * Stage 4: quantization loop * + ****************************************/ + + if (cfg->vbr == vbr_off || cfg->vbr == vbr_abr) { + static FLOAT const fircoef[9] = { + -0.0207887 * 5, -0.0378413 * 5, -0.0432472 * 5, -0.031183 * 5, + 7.79609e-18 * 5, 0.0467745 * 5, 0.10091 * 5, 0.151365 * 5, + 0.187098 * 5 + }; + + int i; + FLOAT f; + + for (i = 0; i < 18; i++) + gfc->sv_enc.pefirbuf[i] = gfc->sv_enc.pefirbuf[i + 1]; + + f = 0.0; + for (gr = 0; gr < cfg->mode_gr; gr++) + for (ch = 0; ch < cfg->channels_out; ch++) + f += pe_use[gr][ch]; + gfc->sv_enc.pefirbuf[18] = f; + + f = gfc->sv_enc.pefirbuf[9]; + for (i = 0; i < 9; i++) + f += (gfc->sv_enc.pefirbuf[i] + gfc->sv_enc.pefirbuf[18 - i]) * fircoef[i]; + + f = (670 * 5 * cfg->mode_gr * cfg->channels_out) / f; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + pe_use[gr][ch] *= f; + } + } + } + switch (cfg->vbr) + { + default: + case vbr_off: + CBR_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + case vbr_abr: + ABR_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + case vbr_rh: + VBR_old_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + case vbr_mt: + case vbr_mtrh: + VBR_new_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + } + + + /**************************************** + * Stage 5: bitstream formatting * + ****************************************/ + + + /* write the frame to the bitstream */ + (void) format_bitstream(gfc); + + /* copy mp3 bit buffer into array */ + mp3count = copy_buffer(gfc, mp3buf, mp3buf_size, 1); + + + if (cfg->write_lame_tag) { + AddVbrFrame(gfc); + } + + if (cfg->analysis && gfc->pinfo != NULL) { + int framesize = 576 * cfg->mode_gr; + for (ch = 0; ch < cfg->channels_out; ch++) { + int j; + for (j = 0; j < FFTOFFSET; j++) + gfc->pinfo->pcmdata[ch][j] = gfc->pinfo->pcmdata[ch][j + framesize]; + for (j = FFTOFFSET; j < 1600; j++) { + gfc->pinfo->pcmdata[ch][j] = inbuf[ch][j - FFTOFFSET]; + } + } + gfc->sv_qnt.masking_lower = 1.0; + + set_frame_pinfo(gfc, masking); + } + + ++gfc->ov_enc.frame_number; + + updateStats(gfc); + + return mp3count; +} diff --git a/pkg/lame/clame/encoder.h b/pkg/lame/clame/encoder.h new file mode 100644 index 0000000..b06a7c6 --- /dev/null +++ b/pkg/lame/clame/encoder.h @@ -0,0 +1,156 @@ +/* + * encoder.h include file + * + * Copyright (c) 2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef LAME_ENCODER_H +#define LAME_ENCODER_H + +/*********************************************************************** +* +* encoder and decoder delays +* +***********************************************************************/ + +/* + * layer III enc->dec delay: 1056 (1057?) (observed) + * layer II enc->dec delay: 480 (481?) (observed) + * + * polyphase 256-16 (dec or enc) = 240 + * mdct 256+32 (9*32) (dec or enc) = 288 + * total: 512+16 + * + * My guess is that delay of polyphase filterbank is actualy 240.5 + * (there are technical reasons for this, see postings in mp3encoder). + * So total Encode+Decode delay = ENCDELAY + 528 + 1 + */ + +/* + * ENCDELAY The encoder delay. + * + * Minimum allowed is MDCTDELAY (see below) + * + * The first 96 samples will be attenuated, so using a value less than 96 + * will result in corrupt data for the first 96-ENCDELAY samples. + * + * suggested: 576 + * set to 1160 to sync with FhG. + */ + +#define ENCDELAY 576 + + + +/* + * make sure there is at least one complete frame after the + * last frame containing real data + * + * Using a value of 288 would be sufficient for a + * a very sophisticated decoder that can decode granule-by-granule instead + * of frame by frame. But lets not assume this, and assume the decoder + * will not decode frame N unless it also has data for frame N+1 + * + */ +/*#define POSTDELAY 288*/ +#define POSTDELAY 1152 + + + +/* + * delay of the MDCT used in mdct.c + * original ISO routines had a delay of 528! + * Takehiro's routines: + */ + +#define MDCTDELAY 48 +#define FFTOFFSET (224+MDCTDELAY) + +/* + * Most decoders, including the one we use, have a delay of 528 samples. + */ + +#define DECDELAY 528 + + +/* number of subbands */ +#define SBLIMIT 32 + +/* parition bands bands */ +#define CBANDS 64 + +/* number of critical bands/scale factor bands where masking is computed*/ +#define SBPSY_l 21 +#define SBPSY_s 12 + +/* total number of scalefactor bands encoded */ +#define SBMAX_l 22 +#define SBMAX_s 13 +#define PSFB21 6 +#define PSFB12 6 + + + +/* FFT sizes */ +#define BLKSIZE 1024 +#define HBLKSIZE (BLKSIZE/2 + 1) +#define BLKSIZE_s 256 +#define HBLKSIZE_s (BLKSIZE_s/2 + 1) + + +/* #define switch_pe 1800 */ +#define NORM_TYPE 0 +#define START_TYPE 1 +#define SHORT_TYPE 2 +#define STOP_TYPE 3 + +/* + * Mode Extention: + * When we are in stereo mode, there are 4 possible methods to store these + * two channels. The stereo modes -m? are using a subset of them. + * + * -ms: MPG_MD_LR_LR + * -mj: MPG_MD_LR_LR and MPG_MD_MS_LR + * -mf: MPG_MD_MS_LR + * -mi: all + */ +#if 0 +#define MPG_MD_LR_LR 0 +#define MPG_MD_LR_I 1 +#define MPG_MD_MS_LR 2 +#define MPG_MD_MS_I 3 +#endif +enum MPEGChannelMode +{ MPG_MD_LR_LR = 0 +, MPG_MD_LR_I = 1 +, MPG_MD_MS_LR = 2 +, MPG_MD_MS_I = 3 +}; + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined +struct lame_internal_flags; +typedef struct lame_internal_flags lame_internal_flags; +#endif + +int lame_encode_mp3_frame(lame_internal_flags * gfc, + sample_t const *inbuf_l, + sample_t const *inbuf_r, unsigned char *mp3buf, int mp3buf_size); + +#endif /* LAME_ENCODER_H */ diff --git a/pkg/lame/clame/fft.c b/pkg/lame/clame/fft.c new file mode 100644 index 0000000..163e155 --- /dev/null +++ b/pkg/lame/clame/fft.c @@ -0,0 +1,339 @@ +/* +** FFT and FHT routines +** Copyright 1988, 1993; Ron Mayer +** Copyright (c) 1999-2000 Takehiro Tominaga +** +** fht(fz,n); +** Does a hartley transform of "n" points in the array "fz". +** +** NOTE: This routine uses at least 2 patented algorithms, and may be +** under the restrictions of a bunch of different organizations. +** Although I wrote it completely myself; it is kind of a derivative +** of a routine I once authored and released under the GPL, so it +** may fall under the free software foundation's restrictions; +** it was worked on as a Stanford Univ project, so they claim +** some rights to it; it was further optimized at work here, so +** I think this company claims parts of it. The patents are +** held by R. Bracewell (the FHT algorithm) and O. Buneman (the +** trig generator), both at Stanford Univ. +** If it were up to me, I'd say go do whatever you want with it; +** but it would be polite to give credit to the following people +** if you use this anywhere: +** Euler - probable inventor of the fourier transform. +** Gauss - probable inventor of the FFT. +** Hartley - probable inventor of the hartley transform. +** Buneman - for a really cool trig generator +** Mayer(me) - for authoring this particular version and +** including all the optimizations in one package. +** Thanks, +** Ron Mayer; mayer@acuson.com +** and added some optimization by +** Mather - idea of using lookup table +** Takehiro - some dirty hack for speed up +*/ + +/* $Id: fft.c,v 1.39 2017/09/06 15:07:29 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "fft.h" + +#include "lame_intrin.h" + + + +#define TRI_SIZE (5-1) /* 1024 = 4**5 */ + +/* fft.c */ + +static const FLOAT costab[TRI_SIZE * 2] = { + 9.238795325112867e-01, 3.826834323650898e-01, + 9.951847266721969e-01, 9.801714032956060e-02, + 9.996988186962042e-01, 2.454122852291229e-02, + 9.999811752826011e-01, 6.135884649154475e-03 +}; + +static void +fht(FLOAT * fz, int n) +{ + const FLOAT *tri = costab; + int k4; + FLOAT *fi, *gi; + FLOAT const *fn; + + n <<= 1; /* to get BLKSIZE, because of 3DNow! ASM routine */ + fn = fz + n; + k4 = 4; + do { + FLOAT s1, c1; + int i, k1, k2, k3, kx; + kx = k4 >> 1; + k1 = k4; + k2 = k4 << 1; + k3 = k2 + k1; + k4 = k2 << 1; + fi = fz; + gi = fi + kx; + do { + FLOAT f0, f1, f2, f3; + f1 = fi[0] - fi[k1]; + f0 = fi[0] + fi[k1]; + f3 = fi[k2] - fi[k3]; + f2 = fi[k2] + fi[k3]; + fi[k2] = f0 - f2; + fi[0] = f0 + f2; + fi[k3] = f1 - f3; + fi[k1] = f1 + f3; + f1 = gi[0] - gi[k1]; + f0 = gi[0] + gi[k1]; + f3 = SQRT2 * gi[k3]; + f2 = SQRT2 * gi[k2]; + gi[k2] = f0 - f2; + gi[0] = f0 + f2; + gi[k3] = f1 - f3; + gi[k1] = f1 + f3; + gi += k4; + fi += k4; + } while (fi < fn); + c1 = tri[0]; + s1 = tri[1]; + for (i = 1; i < kx; i++) { + FLOAT c2, s2; + c2 = 1 - (2 * s1) * s1; + s2 = (2 * s1) * c1; + fi = fz + i; + gi = fz + k1 - i; + do { + FLOAT a, b, g0, f0, f1, g1, f2, g2, f3, g3; + b = s2 * fi[k1] - c2 * gi[k1]; + a = c2 * fi[k1] + s2 * gi[k1]; + f1 = fi[0] - a; + f0 = fi[0] + a; + g1 = gi[0] - b; + g0 = gi[0] + b; + b = s2 * fi[k3] - c2 * gi[k3]; + a = c2 * fi[k3] + s2 * gi[k3]; + f3 = fi[k2] - a; + f2 = fi[k2] + a; + g3 = gi[k2] - b; + g2 = gi[k2] + b; + b = s1 * f2 - c1 * g3; + a = c1 * f2 + s1 * g3; + fi[k2] = f0 - a; + fi[0] = f0 + a; + gi[k3] = g1 - b; + gi[k1] = g1 + b; + b = c1 * g2 - s1 * f3; + a = s1 * g2 + c1 * f3; + gi[k2] = g0 - a; + gi[0] = g0 + a; + fi[k3] = f1 - b; + fi[k1] = f1 + b; + gi += k4; + fi += k4; + } while (fi < fn); + c2 = c1; + c1 = c2 * tri[0] - s1 * tri[1]; + s1 = c2 * tri[1] + s1 * tri[0]; + } + tri += 2; + } while (k4 < n); +} + + +static const unsigned char rv_tbl[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe +}; + +#define ch01(index) (buffer[chn][index]) + +#define ml00(f) (window[i ] * f(i)) +#define ml10(f) (window[i + 0x200] * f(i + 0x200)) +#define ml20(f) (window[i + 0x100] * f(i + 0x100)) +#define ml30(f) (window[i + 0x300] * f(i + 0x300)) + +#define ml01(f) (window[i + 0x001] * f(i + 0x001)) +#define ml11(f) (window[i + 0x201] * f(i + 0x201)) +#define ml21(f) (window[i + 0x101] * f(i + 0x101)) +#define ml31(f) (window[i + 0x301] * f(i + 0x301)) + +#define ms00(f) (window_s[i ] * f(i + k)) +#define ms10(f) (window_s[0x7f - i] * f(i + k + 0x80)) +#define ms20(f) (window_s[i + 0x40] * f(i + k + 0x40)) +#define ms30(f) (window_s[0x3f - i] * f(i + k + 0xc0)) + +#define ms01(f) (window_s[i + 0x01] * f(i + k + 0x01)) +#define ms11(f) (window_s[0x7e - i] * f(i + k + 0x81)) +#define ms21(f) (window_s[i + 0x41] * f(i + k + 0x41)) +#define ms31(f) (window_s[0x3e - i] * f(i + k + 0xc1)) + +void +fft_short(lame_internal_flags const *const gfc, + FLOAT x_real[3][BLKSIZE_s], int chn, const sample_t *const buffer[2]) +{ + int i; + int j; + int b; + +#define window_s gfc->cd_psy->window_s +#define window gfc->cd_psy->window + + for (b = 0; b < 3; b++) { + FLOAT *x = &x_real[b][BLKSIZE_s / 2]; + short const k = (576 / 3) * (b + 1); + j = BLKSIZE_s / 8 - 1; + do { + FLOAT f0, f1, f2, f3, w; + + i = rv_tbl[j << 2]; + + f0 = ms00(ch01); + w = ms10(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ms20(ch01); + w = ms30(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x -= 4; + x[0] = f0 + f2; + x[2] = f0 - f2; + x[1] = f1 + f3; + x[3] = f1 - f3; + + f0 = ms01(ch01); + w = ms11(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ms21(ch01); + w = ms31(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x[BLKSIZE_s / 2 + 0] = f0 + f2; + x[BLKSIZE_s / 2 + 2] = f0 - f2; + x[BLKSIZE_s / 2 + 1] = f1 + f3; + x[BLKSIZE_s / 2 + 3] = f1 - f3; + } while (--j >= 0); + +#undef window +#undef window_s + + gfc->fft_fht(x, BLKSIZE_s / 2); + /* BLKSIZE_s/2 because of 3DNow! ASM routine */ + } +} + +void +fft_long(lame_internal_flags const *const gfc, + FLOAT x[BLKSIZE], int chn, const sample_t *const buffer[2]) +{ + int i; + int jj = BLKSIZE / 8 - 1; + x += BLKSIZE / 2; + +#define window_s gfc->cd_psy->window_s +#define window gfc->cd_psy->window + + do { + FLOAT f0, f1, f2, f3, w; + + i = rv_tbl[jj]; + f0 = ml00(ch01); + w = ml10(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ml20(ch01); + w = ml30(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x -= 4; + x[0] = f0 + f2; + x[2] = f0 - f2; + x[1] = f1 + f3; + x[3] = f1 - f3; + + f0 = ml01(ch01); + w = ml11(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ml21(ch01); + w = ml31(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x[BLKSIZE / 2 + 0] = f0 + f2; + x[BLKSIZE / 2 + 2] = f0 - f2; + x[BLKSIZE / 2 + 1] = f1 + f3; + x[BLKSIZE / 2 + 3] = f1 - f3; + } while (--jj >= 0); + +#undef window +#undef window_s + + gfc->fft_fht(x, BLKSIZE / 2); + /* BLKSIZE/2 because of 3DNow! ASM routine */ +} + +#ifdef HAVE_NASM +extern void fht_3DN(FLOAT * fz, int n); +extern void fht_SSE(FLOAT * fz, int n); +#endif + +void +init_fft(lame_internal_flags * const gfc) +{ + int i; + + /* The type of window used here will make no real difference, but */ + /* in the interest of merging nspsytune stuff - switch to blackman window */ + for (i = 0; i < BLKSIZE; i++) + /* blackman window */ + gfc->cd_psy->window[i] = 0.42 - 0.5 * cos(2 * PI * (i + .5) / BLKSIZE) + + 0.08 * cos(4 * PI * (i + .5) / BLKSIZE); + + for (i = 0; i < BLKSIZE_s / 2; i++) + gfc->cd_psy->window_s[i] = 0.5 * (1.0 - cos(2.0 * PI * (i + 0.5) / BLKSIZE_s)); + + gfc->fft_fht = fht; +#ifdef HAVE_NASM + if (gfc->CPU_features.AMD_3DNow) { + gfc->fft_fht = fht_3DN; + } + else if (gfc->CPU_features.SSE) { + gfc->fft_fht = fht_SSE; + } + else { + gfc->fft_fht = fht; + } +#else +#ifdef HAVE_XMMINTRIN_H +#ifdef MIN_ARCH_SSE + gfc->fft_fht = fht_SSE2; +#endif +#endif +#endif +} diff --git a/pkg/lame/clame/fft.h b/pkg/lame/clame/fft.h new file mode 100644 index 0000000..258df88 --- /dev/null +++ b/pkg/lame/clame/fft.h @@ -0,0 +1,35 @@ +/* + * Fast Fourier Transform include file + * + * Copyright (c) 2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_FFT_H +#define LAME_FFT_H + +void fft_long(lame_internal_flags const *const gfc, FLOAT x_real[BLKSIZE], + int chn, const sample_t *const data[2]); + +void fft_short(lame_internal_flags const *const gfc, FLOAT x_real[3][BLKSIZE_s], + int chn, const sample_t *const data[2]); + +void init_fft(lame_internal_flags * const gfc); + +#endif + +/* End of fft.h */ diff --git a/pkg/lame/clame/gain_analysis.c b/pkg/lame/clame/gain_analysis.c new file mode 100644 index 0000000..c94db78 --- /dev/null +++ b/pkg/lame/clame/gain_analysis.c @@ -0,0 +1,476 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * Improvements and optimizations added by Frank Klemm, and by Marcel Muller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * original coding by Glen Sawyer (mp3gain@hotmail.com) + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) + * -- credit him for all the _good_ programming ;) + * + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +/* + * Here's the deal. Call + * + * InitGainAnalysis ( long samplefreq ); + * + * to initialize everything. Call + * + * AnalyzeSamples ( const Float_t* left_samples, + * const Float_t* right_samples, + * size_t num_samples, + * int num_channels ); + * + * as many times as you want, with as many or as few samples as you want. + * If mono, pass the sample buffer in through left_samples, leave + * right_samples NULL, and make sure num_channels = 1. + * + * GetTitleGain() + * + * will return the recommended dB level change for all samples analyzed + * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). + * + * GetAlbumGain() + * + * will return the recommended dB level change for all samples analyzed + * since InitGainAnalysis() was called and finalized with GetTitleGain(). + * + * Pseudo-code to process an album: + * + * Float_t l_samples [4096]; + * Float_t r_samples [4096]; + * size_t num_samples; + * unsigned int num_songs; + * unsigned int i; + * + * InitGainAnalysis ( 44100 ); + * for ( i = 1; i <= num_songs; i++ ) { + * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) + * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); + * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() ); + * } + * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() ); + */ + +/* + * So here's the main source of potential code confusion: + * + * The filters applied to the incoming samples are IIR filters, + * meaning they rely on up to number of previous samples + * AND up to number of previous filtered samples. + * + * I set up the AnalyzeSamples routine to minimize memory usage and interface + * complexity. The speed isn't compromised too much (I don't think), but the + * internal complexity is higher than it should be for such a relatively + * simple routine. + * + * Optimization/clarity suggestions are welcome. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "lame.h" +#include "machine.h" +#include "gain_analysis.h" + +/* for each filter: */ +/* [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */ + +#ifdef WIN32 +#pragma warning ( disable : 4305 ) +#endif + + +/*lint -save -e736 loss of precision */ +static const Float_t ABYule[9][multiple_of(4, 2 * YULE_ORDER + 1)] = { + /* 20 18 16 14 12 10 8 6 4 2 0 19 17 15 13 11 9 7 5 3 1 */ + { 0.00288463683916, 0.00012025322027, 0.00306428023191, 0.00594298065125, -0.02074045215285, 0.02161526843274, -0.01655260341619, -0.00009291677959, -0.00123395316851, -0.02160367184185, 0.03857599435200, 0.13919314567432, -0.86984376593551, 2.75465861874613, -5.87257861775999, 9.48293806319790,-12.28759895145294, 13.05504219327545,-11.34170355132042, 7.81501653005538, -3.84664617118067}, + {-0.00187763777362, 0.00674613682247, -0.00240879051584, 0.01624864962975, -0.02596338512915, 0.02245293253339, -0.00834990904936, -0.00851165645469, -0.00848709379851, -0.02911007808948, 0.05418656406430, 0.13149317958808, -0.75104302451432, 2.19611684890774, -4.39470996079559, 6.85401540936998, -8.81498681370155, 9.47693607801280, -8.54751527471874, 6.36317777566148, -3.47845948550071}, + {-0.00881362733839, 0.00651420667831, -0.01390589421898, 0.03174092540049, 0.00222312597743, 0.04781476674921, -0.05588393329856, 0.02163541888798, -0.06247880153653, -0.09331049056315, 0.15457299681924, 0.02347897407020, -0.05032077717131, 0.16378164858596, -0.45953458054983, 1.00595954808547, -1.67148153367602, 2.23697657451713, -2.64577170229825, 2.84868151156327, -2.37898834973084}, + {-0.02950134983287, 0.00205861885564, -0.00000828086748, 0.06276101321749, -0.00584456039913, -0.02364141202522, -0.00915702933434, 0.03282930172664, -0.08587323730772, -0.22613988682123, 0.30296907319327, 0.00302439095741, 0.02005851806501, 0.04500235387352, -0.22138138954925, 0.39120800788284, -0.22638893773906, -0.16276719120440, -0.25656257754070, 1.07977492259970, -1.61273165137247}, + {-0.01760176568150, -0.01635381384540, 0.00832043980773, 0.05724228140351, -0.00589500224440, -0.00469977914380, -0.07834489609479, 0.11921148675203, -0.11828570177555, -0.25572241425570, 0.33642304856132, 0.02977207319925, -0.04237348025746, 0.08333755284107, -0.04067510197014, -0.12453458140019, 0.47854794562326, -0.80774944671438, 0.12205022308084, 0.87350271418188, -1.49858979367799}, + { 0.00541907748707, -0.03193428438915, -0.01863887810927, 0.10478503600251, 0.04097565135648, -0.12398163381748, 0.04078262797139, -0.01419140100551, -0.22784394429749, -0.14351757464547, 0.44915256608450, 0.03222754072173, 0.05784820375801, 0.06747620744683, 0.00613424350682, 0.22199650564824, -0.42029820170918, 0.00213767857124, -0.37256372942400, 0.29661783706366, -0.62820619233671}, + {-0.00588215443421, -0.03788984554840, 0.08647503780351, 0.00647310677246, -0.27562961986224, 0.30931782841830, -0.18901604199609, 0.16744243493672, 0.16242137742230, -0.75464456939302, 0.56619470757641, 0.01807364323573, 0.01639907836189, -0.04784254229033, 0.06739368333110, -0.33032403314006, 0.45054734505008, 0.00819999645858, -0.26806001042947, 0.29156311971249, -1.04800335126349}, + {-0.00749618797172, -0.03721611395801, 0.06920467763959, 0.01628462406333, -0.25344790059353, 0.15558449135573, 0.02377945217615, 0.17520704835522, -0.14289799034253, -0.53174909058578, 0.58100494960553, 0.01818801111503, 0.02442357316099, -0.02505961724053, -0.05246019024463, -0.23313271880868, 0.38952639978999, 0.14728154134330, -0.20256413484477, -0.31863563325245, -0.51035327095184}, + {-0.02217936801134, 0.04788665548180, -0.04060034127000, -0.11202315195388, -0.02459864859345, 0.14590772289388, -0.10214864179676, 0.04267842219415, -0.00275953611929, -0.42163034350696, 0.53648789255105, 0.04704409688120, 0.05477720428674, -0.18823009262115, -0.17556493366449, 0.15113130533216, 0.26408300200955, -0.04678328784242, -0.03424681017675, -0.43193942311114, -0.25049871956020} +}; + +static const Float_t ABButter[9][multiple_of(4, 2 * BUTTER_ORDER + 1)] = { + /* 5 4 3 2 1 */ + {0.98621192462708, 0.97261396931306, -1.97242384925416, -1.97223372919527, 0.98621192462708}, + {0.98500175787242, 0.97022847566350, -1.97000351574484, -1.96977855582618, 0.98500175787242}, + {0.97938932735214, 0.95920349965459, -1.95877865470428, -1.95835380975398, 0.97938932735214}, + {0.97531843204928, 0.95124613669835, -1.95063686409857, -1.95002759149878, 0.97531843204928}, + {0.97316523498161, 0.94705070426118, -1.94633046996323, -1.94561023566527, 0.97316523498161}, + {0.96454515552826, 0.93034775234268, -1.92909031105652, -1.92783286977036, 0.96454515552826}, + {0.96009142950541, 0.92177618768381, -1.92018285901082, -1.91858953033784, 0.96009142950541}, + {0.95856916599601, 0.91885558323625, -1.91713833199203, -1.91542108074780, 0.95856916599601}, + {0.94597685600279, 0.89487434461664, -1.89195371200558, -1.88903307939452, 0.94597685600279} +}; + +/*lint -restore */ + +#ifdef WIN32 +#pragma warning ( default : 4305 ) +#endif + +/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */ + +static void +filterYule(const Float_t * input, Float_t * output, size_t nSamples, const Float_t * const kernel) +{ + while (nSamples--) { + Float_t y0 = input[-10] * kernel[ 0]; + Float_t y2 = input[ -9] * kernel[ 1]; + Float_t y4 = input[ -8] * kernel[ 2]; + Float_t y6 = input[ -7] * kernel[ 3]; + Float_t s00 = y0 + y2 + y4 + y6; + Float_t y8 = input[ -6] * kernel[ 4]; + Float_t yA = input[ -5] * kernel[ 5]; + Float_t yC = input[ -4] * kernel[ 6]; + Float_t yE = input[ -3] * kernel[ 7]; + Float_t s01 = y8 + yA + yC + yE; + Float_t yG = input[ -2] * kernel[ 8] + input[ -1] * kernel[ 9]; + Float_t yK = input[ 0] * kernel[10]; + + Float_t s1 = s00 + s01 + yG + yK; + + Float_t x1 = output[-10] * kernel[11] + output[ -9] * kernel[12]; + Float_t x5 = output[ -8] * kernel[13] + output[ -7] * kernel[14]; + Float_t x9 = output[ -6] * kernel[15] + output[ -5] * kernel[16]; + Float_t xD = output[ -4] * kernel[17] + output[ -3] * kernel[18]; + Float_t xH = output[ -2] * kernel[19] + output[ -1] * kernel[20]; + + Float_t s2 = x1 + x5 + x9 + xD + xH; + + output[0] = (Float_t)(s1 - s2); + + ++output; + ++input; + } +} + +static void +filterButter(const Float_t * input, Float_t * output, size_t nSamples, const Float_t * const kernel) +{ + while (nSamples--) { + Float_t s1 = input[-2] * kernel[0] + input[-1] * kernel[2] + input[ 0] * kernel[4]; + Float_t s2 = output[-2] * kernel[1] + output[-1] * kernel[3]; + output[0] = (Float_t)(s1 - s2); + ++output; + ++input; + } +} + + + +static int ResetSampleFrequency(replaygain_t * rgData, long samplefreq); + +/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */ + +int +ResetSampleFrequency(replaygain_t * rgData, long samplefreq) +{ + /* zero out initial values, only first MAX_ORDER values */ + memset(rgData->linprebuf, 0, MAX_ORDER * sizeof(*rgData->linprebuf)); + memset(rgData->rinprebuf, 0, MAX_ORDER * sizeof(*rgData->rinprebuf)); + memset(rgData->lstepbuf, 0, MAX_ORDER * sizeof(*rgData->lstepbuf)); + memset(rgData->rstepbuf, 0, MAX_ORDER * sizeof(*rgData->rstepbuf)); + memset(rgData->loutbuf, 0, MAX_ORDER * sizeof(*rgData->loutbuf)); + memset(rgData->routbuf, 0, MAX_ORDER * sizeof(*rgData->routbuf)); + + switch ((int) (samplefreq)) { + case 48000: + rgData->freqindex = 0; + break; + case 44100: + rgData->freqindex = 1; + break; + case 32000: + rgData->freqindex = 2; + break; + case 24000: + rgData->freqindex = 3; + break; + case 22050: + rgData->freqindex = 4; + break; + case 16000: + rgData->freqindex = 5; + break; + case 12000: + rgData->freqindex = 6; + break; + case 11025: + rgData->freqindex = 7; + break; + case 8000: + rgData->freqindex = 8; + break; + default: + return INIT_GAIN_ANALYSIS_ERROR; + } + + rgData->sampleWindow = + (samplefreq * RMS_WINDOW_TIME_NUMERATOR + RMS_WINDOW_TIME_DENOMINATOR - + 1) / RMS_WINDOW_TIME_DENOMINATOR; + + rgData->lsum = 0.; + rgData->rsum = 0.; + rgData->totsamp = 0; + + memset(rgData->A, 0, sizeof(rgData->A)); + + return INIT_GAIN_ANALYSIS_OK; +} + +int +InitGainAnalysis(replaygain_t * rgData, long samplefreq) +{ + if (ResetSampleFrequency(rgData, samplefreq) != INIT_GAIN_ANALYSIS_OK) { + return INIT_GAIN_ANALYSIS_ERROR; + } + + rgData->linpre = rgData->linprebuf + MAX_ORDER; + rgData->rinpre = rgData->rinprebuf + MAX_ORDER; + rgData->lstep = rgData->lstepbuf + MAX_ORDER; + rgData->rstep = rgData->rstepbuf + MAX_ORDER; + rgData->lout = rgData->loutbuf + MAX_ORDER; + rgData->rout = rgData->routbuf + MAX_ORDER; + + memset(rgData->B, 0, sizeof(rgData->B)); + + return INIT_GAIN_ANALYSIS_OK; +} + +/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */ + +int +AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples, const Float_t * right_samples, + size_t num_samples, int num_channels) +{ + const Float_t *curleft; + const Float_t *curright; + long batchsamples; + long cursamples; + long cursamplepos; + int i; + Float_t sum_l, sum_r; + + if (num_samples == 0) + return GAIN_ANALYSIS_OK; + + cursamplepos = 0; + batchsamples = (long) num_samples; + + switch (num_channels) { + case 1: + right_samples = left_samples; + break; + case 2: + break; + default: + return GAIN_ANALYSIS_ERROR; + } + + if (num_samples < MAX_ORDER) { + memcpy(rgData->linprebuf + MAX_ORDER, left_samples, num_samples * sizeof(Float_t)); + memcpy(rgData->rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t)); + } + else { + memcpy(rgData->linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t)); + memcpy(rgData->rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t)); + } + + while (batchsamples > 0) { + cursamples = batchsamples > rgData->sampleWindow - rgData->totsamp ? + rgData->sampleWindow - rgData->totsamp : batchsamples; + if (cursamplepos < MAX_ORDER) { + curleft = rgData->linpre + cursamplepos; + curright = rgData->rinpre + cursamplepos; + if (cursamples > MAX_ORDER - cursamplepos) + cursamples = MAX_ORDER - cursamplepos; + } + else { + curleft = left_samples + cursamplepos; + curright = right_samples + cursamplepos; + } + + YULE_FILTER(curleft, rgData->lstep + rgData->totsamp, cursamples, + ABYule[rgData->freqindex]); + YULE_FILTER(curright, rgData->rstep + rgData->totsamp, cursamples, + ABYule[rgData->freqindex]); + + BUTTER_FILTER(rgData->lstep + rgData->totsamp, rgData->lout + rgData->totsamp, cursamples, + ABButter[rgData->freqindex]); + BUTTER_FILTER(rgData->rstep + rgData->totsamp, rgData->rout + rgData->totsamp, cursamples, + ABButter[rgData->freqindex]); + + curleft = rgData->lout + rgData->totsamp; /* Get the squared values */ + curright = rgData->rout + rgData->totsamp; + + sum_l = 0; + sum_r = 0; + i = cursamples & 0x03; + while (i--) { + Float_t const l = *curleft++; + Float_t const r = *curright++; + sum_l += l * l; + sum_r += r * r; + } + i = cursamples / 4; + while (i--) { + Float_t l0 = curleft[0] * curleft[0]; + Float_t l1 = curleft[1] * curleft[1]; + Float_t l2 = curleft[2] * curleft[2]; + Float_t l3 = curleft[3] * curleft[3]; + Float_t sl = l0 + l1 + l2 + l3; + Float_t r0 = curright[0] * curright[0]; + Float_t r1 = curright[1] * curright[1]; + Float_t r2 = curright[2] * curright[2]; + Float_t r3 = curright[3] * curright[3]; + Float_t sr = r0 + r1 + r2 + r3; + sum_l += sl; + curleft += 4; + sum_r += sr; + curright += 4; + } + rgData->lsum += sum_l; + rgData->rsum += sum_r; + + batchsamples -= cursamples; + cursamplepos += cursamples; + rgData->totsamp += cursamples; + if (rgData->totsamp == rgData->sampleWindow) { /* Get the Root Mean Square (RMS) for this set of samples */ + double const val = + STEPS_per_dB * 10. * log10((rgData->lsum + rgData->rsum) / rgData->totsamp * 0.5 + + 1.e-37); + size_t ival = (val <= 0) ? 0 : (size_t) val; + if (ival >= sizeof(rgData->A) / sizeof(*(rgData->A))) + ival = sizeof(rgData->A) / sizeof(*(rgData->A)) - 1; + rgData->A[ival]++; + rgData->lsum = rgData->rsum = 0.; + memmove(rgData->loutbuf, rgData->loutbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + memmove(rgData->routbuf, rgData->routbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + memmove(rgData->lstepbuf, rgData->lstepbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + memmove(rgData->rstepbuf, rgData->rstepbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + rgData->totsamp = 0; + } + if (rgData->totsamp > rgData->sampleWindow) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */ + return GAIN_ANALYSIS_ERROR; + } + if (num_samples < MAX_ORDER) { + memmove(rgData->linprebuf, rgData->linprebuf + num_samples, + (MAX_ORDER - num_samples) * sizeof(Float_t)); + memmove(rgData->rinprebuf, rgData->rinprebuf + num_samples, + (MAX_ORDER - num_samples) * sizeof(Float_t)); + memcpy(rgData->linprebuf + MAX_ORDER - num_samples, left_samples, + num_samples * sizeof(Float_t)); + memcpy(rgData->rinprebuf + MAX_ORDER - num_samples, right_samples, + num_samples * sizeof(Float_t)); + } + else { + memcpy(rgData->linprebuf, left_samples + num_samples - MAX_ORDER, + MAX_ORDER * sizeof(Float_t)); + memcpy(rgData->rinprebuf, right_samples + num_samples - MAX_ORDER, + MAX_ORDER * sizeof(Float_t)); + } + + return GAIN_ANALYSIS_OK; +} + + +static Float_t +analyzeResult(uint32_t const *Array, size_t len) +{ + uint32_t elems; + uint32_t upper; + uint32_t sum; + size_t i; + + elems = 0; + for (i = 0; i < len; i++) + elems += Array[i]; + if (elems == 0) + return GAIN_NOT_ENOUGH_SAMPLES; + + upper = (uint32_t) ceil(elems * (1. - RMS_PERCENTILE)); + sum = 0; + for (i = len; i-- > 0;) { + sum += Array[i]; + if (sum >= upper) { + break; + } + } + + return (Float_t) ((Float_t) PINK_REF - (Float_t) i / (Float_t) STEPS_per_dB); +} + + +Float_t +GetTitleGain(replaygain_t * rgData) +{ + Float_t retval; + unsigned int i; + + retval = analyzeResult(rgData->A, sizeof(rgData->A) / sizeof(*(rgData->A))); + + for (i = 0; i < sizeof(rgData->A) / sizeof(*(rgData->A)); i++) { + rgData->B[i] += rgData->A[i]; + rgData->A[i] = 0; + } + + for (i = 0; i < MAX_ORDER; i++) + rgData->linprebuf[i] = rgData->lstepbuf[i] + = rgData->loutbuf[i] + = rgData->rinprebuf[i] + = rgData->rstepbuf[i] + = rgData->routbuf[i] = 0.f; + + rgData->totsamp = 0; + rgData->lsum = rgData->rsum = 0.; + return retval; +} + +#if 0 +static Float_t GetAlbumGain(replaygain_t const* rgData); + +Float_t +GetAlbumGain(replaygain_t const* rgData) +{ + return analyzeResult(rgData->B, sizeof(rgData->B) / sizeof(*(rgData->B))); +} +#endif + +/* end of gain_analysis.c */ diff --git a/pkg/lame/clame/gain_analysis.h b/pkg/lame/clame/gain_analysis.h new file mode 100644 index 0000000..a6b56ab --- /dev/null +++ b/pkg/lame/clame/gain_analysis.h @@ -0,0 +1,109 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * coding by Glen Sawyer (mp3gain@hotmail.com) 735 W 255 N, Orem, UT 84057-4505 USA + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +#ifndef GAIN_ANALYSIS_H +#define GAIN_ANALYSIS_H + +#ifdef HAVE_INTTYPES_H +# include +#else +# ifdef HAVE_STDINT_H +# include +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + + typedef sample_t Float_t; /* Type used for filtering */ + + +#define PINK_REF 64.82 /* 298640883795 */ /* calibration value for 89dB */ + + +#define YULE_ORDER 10 +#define BUTTER_ORDER 2 +#define YULE_FILTER filterYule +#define BUTTER_FILTER filterButter +#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */ +#define MAX_SAMP_FREQ 48000L /* maximum allowed sample frequency [Hz] */ +#define RMS_WINDOW_TIME_NUMERATOR 1L +#define RMS_WINDOW_TIME_DENOMINATOR 20L /* numerator / denominator = time slice size [s] */ +#define STEPS_per_dB 100 /* Table entries per dB */ +#define MAX_dB 120 /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */ + + enum { GAIN_NOT_ENOUGH_SAMPLES = -24601, GAIN_ANALYSIS_ERROR = 0, GAIN_ANALYSIS_OK = + 1, INIT_GAIN_ANALYSIS_ERROR = 0, INIT_GAIN_ANALYSIS_OK = 1 + }; + + enum { MAX_ORDER = (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) + , MAX_SAMPLES_PER_WINDOW = ((MAX_SAMP_FREQ * RMS_WINDOW_TIME_NUMERATOR) / RMS_WINDOW_TIME_DENOMINATOR + 1) /* max. Samples per Time slice */ + }; + + struct replaygain_data { + Float_t linprebuf[MAX_ORDER * 2]; + Float_t *linpre; /* left input samples, with pre-buffer */ + Float_t lstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *lstep; /* left "first step" (i.e. post first filter) samples */ + Float_t loutbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *lout; /* left "out" (i.e. post second filter) samples */ + Float_t rinprebuf[MAX_ORDER * 2]; + Float_t *rinpre; /* right input samples ... */ + Float_t rstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *rstep; + Float_t routbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *rout; + long sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */ + long totsamp; + double lsum; + double rsum; + int freqindex; + int first; + uint32_t A[STEPS_per_dB * MAX_dB]; + uint32_t B[STEPS_per_dB * MAX_dB]; + + }; +#ifndef replaygain_data_defined +#define replaygain_data_defined + typedef struct replaygain_data replaygain_t; +#endif + + + + + int InitGainAnalysis(replaygain_t * rgData, long samplefreq); + int AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples, + const Float_t * right_samples, size_t num_samples, int num_channels); + Float_t GetTitleGain(replaygain_t * rgData); + + +#ifdef __cplusplus +} +#endif +#endif /* GAIN_ANALYSIS_H */ diff --git a/pkg/lame/clame/id3tag.c b/pkg/lame/clame/id3tag.c new file mode 100644 index 0000000..ac48510 --- /dev/null +++ b/pkg/lame/clame/id3tag.c @@ -0,0 +1,1926 @@ +/* + * id3tag.c -- Write ID3 version 1 and 2 tags. + * + * Copyright (C) 2000 Don Melton + * Copyright (C) 2011-2017 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * HISTORY: This source file is part of LAME (see http://www.mp3dev.org) + * and was originally adapted by Conrad Sanderson + * from mp3info by Ricardo Cerqueira to write only ID3 version 1 + * tags. Don Melton COMPLETELY rewrote it to support version + * 2 tags and be more conformant to other standards while remaining flexible. + * + * NOTE: See http://id3.org/ for more information about ID3 tag formats. + */ + +/* $Id: id3tag.c,v 1.80 2017/08/28 15:39:51 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef STDC_HEADERS +# include +# include +# include +# include +#else +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr(), *strrchr(); +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "id3tag.h" +#include "lame_global_flags.h" +#include "util.h" +#include "bitstream.h" + + +static const char *const genre_names[] = { + /* + * NOTE: The spelling of these genre names is identical to those found in + * Winamp and mp3info. + */ + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", + "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", + "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", + "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", + "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", + "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock", + "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", + "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", + "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", + "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", + "Native US", "Cabaret", "New Wave", "Psychedelic", "Rave", + "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", + "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", + "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", + "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", + "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", + "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", + "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", + "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", + "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", + "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", + "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", + "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta", + "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", + "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "SynthPop" +}; + +#define GENRE_NAME_COUNT \ + ((int)(sizeof genre_names / sizeof (const char *const))) + +static const int genre_alpha_map[] = { + 123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0, + 107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2, + 139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84, + 80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35, + 100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64, + 133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92, + 67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21, + 111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130, + 144, 60, 70, 31, 72, 27, 28 +}; + +#define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int))) + +#define GENRE_INDEX_OTHER 12 + + +#define FRAME_ID(a, b, c, d) \ + ( ((unsigned long)(a) << 24) \ + | ((unsigned long)(b) << 16) \ + | ((unsigned long)(c) << 8) \ + | ((unsigned long)(d) << 0) ) + +typedef enum UsualStringIDs { ID_TITLE = FRAME_ID('T', 'I', 'T', '2') + , ID_ARTIST = FRAME_ID('T', 'P', 'E', '1') + , ID_ALBUM = FRAME_ID('T', 'A', 'L', 'B') + , ID_GENRE = FRAME_ID('T', 'C', 'O', 'N') + , ID_ENCODER = FRAME_ID('T', 'S', 'S', 'E') + , ID_PLAYLENGTH = FRAME_ID('T', 'L', 'E', 'N') + , ID_COMMENT = FRAME_ID('C', 'O', 'M', 'M') /* full text string */ +} UsualStringIDs; + +typedef enum NumericStringIDs { ID_DATE = FRAME_ID('T', 'D', 'A', 'T') /* "ddMM" */ + , ID_TIME = FRAME_ID('T', 'I', 'M', 'E') /* "hhmm" */ + , ID_TPOS = FRAME_ID('T', 'P', 'O', 'S') /* '0'-'9' and '/' allowed */ + , ID_TRACK = FRAME_ID('T', 'R', 'C', 'K') /* '0'-'9' and '/' allowed */ + , ID_YEAR = FRAME_ID('T', 'Y', 'E', 'R') /* "yyyy" */ +} NumericStringIDs; + +typedef enum MiscIDs { ID_TXXX = FRAME_ID('T', 'X', 'X', 'X') + , ID_WXXX = FRAME_ID('W', 'X', 'X', 'X') + , ID_SYLT = FRAME_ID('S', 'Y', 'L', 'T') + , ID_APIC = FRAME_ID('A', 'P', 'I', 'C') + , ID_GEOB = FRAME_ID('G', 'E', 'O', 'B') + , ID_PCNT = FRAME_ID('P', 'C', 'N', 'T') + , ID_AENC = FRAME_ID('A', 'E', 'N', 'C') + , ID_LINK = FRAME_ID('L', 'I', 'N', 'K') + , ID_ENCR = FRAME_ID('E', 'N', 'C', 'R') + , ID_GRID = FRAME_ID('G', 'R', 'I', 'D') + , ID_PRIV = FRAME_ID('P', 'R', 'I', 'V') + , ID_USLT = FRAME_ID('U', 'S', 'L', 'T') /* full text string */ + , ID_USER = FRAME_ID('U', 'S', 'E', 'R') /* full text string */ + , ID_PCST = FRAME_ID('P', 'C', 'S', 'T') /* iTunes Podcast indicator, only presence important */ + , ID_WFED = FRAME_ID('W', 'F', 'E', 'D') /* iTunes Podcast URL as TEXT FRAME !!! violates standard */ +} MiscIDs; + + +static int +frame_id_matches(int id, int mask) +{ + int result = 0, i, window = 0xff; + for (i = 0; i < 4; ++i, window <<= 8) { + int const mw = (mask & window); + int const iw = (id & window); + if (mw != 0 && mw != iw) { + result |= iw; + } + } + return result; +} + +static int +isFrameIdMatching(int id, int mask) +{ + return frame_id_matches(id, mask) == 0 ? 1 : 0; +} + +static int +test_tag_spec_flags(lame_internal_flags const *gfc, unsigned int tst) +{ + return (gfc->tag_spec.flags & tst) != 0u ? 1 : 0; +} + +#if 0 +static void +debug_tag_spec_flags(lame_internal_flags * gfc, const char* info) +{ + MSGF(gfc, "%s\n", info); + MSGF(gfc, "CHANGED_FLAG : %d\n", test_tag_spec_flags(gfc, CHANGED_FLAG )); + MSGF(gfc, "ADD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, ADD_V2_FLAG )); + MSGF(gfc, "V1_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V1_ONLY_FLAG )); + MSGF(gfc, "V2_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V2_ONLY_FLAG )); + MSGF(gfc, "SPACE_V1_FLAG : %d\n", test_tag_spec_flags(gfc, SPACE_V1_FLAG)); + MSGF(gfc, "PAD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, PAD_V2_FLAG )); +} +#endif + +static int +is_lame_internal_flags_null(lame_t gfp) +{ + return (gfp && gfp->internal_flags) ? 0 : 1; +} + +static int +id3v2_add_ucs2_lng(lame_t gfp, uint32_t frame_id, unsigned short const *desc, unsigned short const *text); +static int +id3v2_add_latin1_lng(lame_t gfp, uint32_t frame_id, char const *desc, char const *text); + + +static void +copyV1ToV2(lame_t gfp, int frame_id, char const *s) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc != 0) { + unsigned int flags = gfc->tag_spec.flags; + id3v2_add_latin1_lng(gfp, frame_id, 0, s); + gfc->tag_spec.flags = flags; +#if 0 + debug_tag_spec_flags(gfc, "copyV1ToV2"); +#endif + } +} + + +static void +id3v2AddLameVersion(lame_t gfp) +{ + char buffer[1024]; + const char *b = get_lame_os_bitness(); + const char *v = get_lame_version(); + const char *u = get_lame_url(); + const size_t lenb = strlen(b); + + if (lenb > 0) { + sprintf(buffer, "LAME %s version %s (%s)", b, v, u); + } + else { + sprintf(buffer, "LAME version %s (%s)", v, u); + } + copyV1ToV2(gfp, ID_ENCODER, buffer); +} + +static void +id3v2AddAudioDuration(lame_t gfp, double ms) +{ + SessionConfig_t const *const cfg = &gfp->internal_flags->cfg; /* caller checked pointers */ + char buffer[1024]; + double const max_ulong = MAX_U_32_NUM; + unsigned long playlength_ms; + + ms *= 1000; + ms /= cfg->samplerate_in; + if (ms > max_ulong) { + playlength_ms = max_ulong; + } + else if (ms < 0) { + playlength_ms = 0; + } + else { + playlength_ms = ms; + } + sprintf(buffer, "%lu", playlength_ms); + copyV1ToV2(gfp, ID_PLAYLENGTH, buffer); +} + +void +id3tag_genre_list(void (*handler) (int, const char *, void *), void *cookie) +{ + if (handler) { + int i; + for (i = 0; i < GENRE_NAME_COUNT; ++i) { + if (i < GENRE_ALPHA_COUNT) { + int j = genre_alpha_map[i]; + handler(j, genre_names[j], cookie); + } + } + } +} + +#define GENRE_NUM_UNKNOWN 255 + + + +void +id3tag_init(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + free_id3tag(gfc); + memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec); + gfc->tag_spec.genre_id3v1 = GENRE_NUM_UNKNOWN; + gfc->tag_spec.padding_size = 128; + id3v2AddLameVersion(gfp); +} + + + +void +id3tag_add_v2(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V1_ONLY_FLAG; + gfc->tag_spec.flags |= ADD_V2_FLAG; +} + +void +id3tag_v1_only(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG); + gfc->tag_spec.flags |= V1_ONLY_FLAG; +} + +void +id3tag_v2_only(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V1_ONLY_FLAG; + gfc->tag_spec.flags |= V2_ONLY_FLAG; +} + +void +id3tag_space_v1(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V2_ONLY_FLAG; + gfc->tag_spec.flags |= SPACE_V1_FLAG; +} + +void +id3tag_pad_v2(lame_t gfp) +{ + id3tag_set_pad(gfp, 128); +} + +void +id3tag_set_pad(lame_t gfp, size_t n) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V1_ONLY_FLAG; + gfc->tag_spec.flags |= PAD_V2_FLAG; + gfc->tag_spec.flags |= ADD_V2_FLAG; + gfc->tag_spec.padding_size = (unsigned int)n; +} + +static int +hasUcs2ByteOrderMarker(unsigned short bom) +{ + if (bom == 0xFFFEu || bom == 0xFEFFu) { + return 1; + } + return 0; +} + + +static unsigned short +swap_bytes(unsigned short w) +{ + return (0xff00u & (w << 8)) | (0x00ffu & (w >> 8)); +} + + +static unsigned short +toLittleEndian(unsigned short bom, unsigned short c) +{ + if (bom == 0xFFFEu) { + return swap_bytes(c); + } + return c; +} + +static unsigned short +fromLatin1Char(const unsigned short* s, unsigned short c) +{ + if (s[0] == 0xFFFEu) { + return swap_bytes(c); + } + return c; +} + + +static size_t +local_strdup(char **dst, const char *src) +{ + if (dst == 0) { + return 0; + } + free(*dst); + *dst = 0; + if (src != 0) { + size_t n; + for (n = 0; src[n] != 0; ++n) { /* calc src string length */ + } + if (n > 0) { /* string length without zero termination */ + assert(sizeof(*src) == sizeof(**dst)); + *dst = lame_calloc(char, n + 1); + if (*dst != 0) { + memcpy(*dst, src, n * sizeof(**dst)); + (*dst)[n] = 0; + return n; + } + } + } + return 0; +} + +static size_t +local_ucs2_strdup(unsigned short **dst, unsigned short const *src) +{ + if (dst == 0) { + return 0; + } + free(*dst); /* free old string pointer */ + *dst = 0; + if (src != 0) { + size_t n; + for (n = 0; src[n] != 0; ++n) { /* calc src string length */ + } + if (n > 0) { /* string length without zero termination */ + assert(sizeof(*src) >= 2); + assert(sizeof(*src) == sizeof(**dst)); + *dst = lame_calloc(unsigned short, n + 1); + if (*dst != 0) { + memcpy(*dst, src, n * sizeof(**dst)); + (*dst)[n] = 0; + return n; + } + } + } + return 0; +} + + +static size_t +local_ucs2_strlen(unsigned short const *s) +{ + size_t n = 0; + if (s != 0) { + while (*s++) { + ++n; + } + } + return n; +} + + +static size_t +local_ucs2_substr(unsigned short** dst, unsigned short const* src, size_t start, size_t end) +{ + size_t const len = 1 + 1 + ((start < end) ? (end - start) : 0); + size_t n = 0; + unsigned short *ptr = lame_calloc(unsigned short, len); + *dst = ptr; + if (ptr == 0 || src == 0) { + return 0; + } + if (hasUcs2ByteOrderMarker(src[0])) { + ptr[n++] = src[0]; + if (start == 0) { + ++start; + } + } + while (start < end) { + ptr[n++] = src[start++]; + } + ptr[n] = 0; + return n; +} + +static int +local_ucs2_pos(unsigned short const* str, unsigned short c) +{ + int i; + for (i = 0; str != 0 && str[i] != 0; ++i) { + if (str[i] == c) { + return i; + } + } + return -1; +} + +static int +local_char_pos(char const* str, char c) +{ + int i; + for (i = 0; str != 0 && str[i] != 0; ++i) { + if (str[i] == c) { + return i; + } + } + return -1; +} + +static int +maybeLatin1(unsigned short const* text) +{ + if (text) { + unsigned short bom = *text++; + while (*text) { + unsigned short c = toLittleEndian(bom, *text++); + if (c > 0x00fe) return 0; + } + } + return 1; +} + +static int searchGenre(char const* genre); +static int sloppySearchGenre(char const* genre); + +static int +lookupGenre(char const* genre) +{ + char *str; + int num = strtol(genre, &str, 10); + /* is the input a string or a valid number? */ + if (*str) { + num = searchGenre(genre); + if (num == GENRE_NAME_COUNT) { + num = sloppySearchGenre(genre); + } + if (num == GENRE_NAME_COUNT) { + return -2; /* no common genre text found */ + } + } + else { + if ((num < 0) || (num >= GENRE_NAME_COUNT)) { + return -1; /* number unknown */ + } + } + return num; +} + +static unsigned char * +writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n); + +static char* +local_strdup_utf16_to_latin1(unsigned short const* utf16) +{ + size_t len = local_ucs2_strlen(utf16); + unsigned char* latin1 = lame_calloc(unsigned char, len+1); + writeLoBytes(latin1, utf16, len); + return (char*)latin1; +} + + +static int +id3tag_set_genre_utf16(lame_t gfp, unsigned short const* text) +{ + lame_internal_flags* gfc = gfp->internal_flags; + int ret; + if (text == 0) { + return -3; + } + if (!hasUcs2ByteOrderMarker(text[0])) { + return -3; + } + if (maybeLatin1(text)) { + char* latin1 = local_strdup_utf16_to_latin1(text); + int num = lookupGenre(latin1); + free(latin1); + if (num == -1) return -1; /* number out of range */ + if (num >= 0) { /* common genre found */ + gfc->tag_spec.flags |= CHANGED_FLAG; + gfc->tag_spec.genre_id3v1 = num; + copyV1ToV2(gfp, ID_GENRE, genre_names[num]); + return 0; + } + } + ret = id3v2_add_ucs2_lng(gfp, ID_GENRE, 0, text); + if (ret == 0) { + gfc->tag_spec.flags |= CHANGED_FLAG; + gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER; + } + return ret; +} + +/* +Some existing options for ID3 tag can be specified by --tv option +as follows. +--tt , --tv TIT2=value +--ta , --tv TPE1=value +--tl , --tv TALB=value +--ty , --tv TYER=value +--tn , --tv TRCK=value +--tg , --tv TCON=value +(although some are not exactly same)*/ + +int +id3tag_set_albumart(lame_t gfp, const char *image, size_t size) +{ + int mimetype = MIMETYPE_NONE; + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; + + if (image != 0) { + unsigned char const *data = (unsigned char const *) image; + /* determine MIME type from the actual image data */ + if (2 < size && data[0] == 0xFF && data[1] == 0xD8) { + mimetype = MIMETYPE_JPEG; + } + else if (4 < size && data[0] == 0x89 && strncmp((const char *) &data[1], "PNG", 3) == 0) { + mimetype = MIMETYPE_PNG; + } + else if (4 < size && strncmp((const char *) data, "GIF8", 4) == 0) { + mimetype = MIMETYPE_GIF; + } + else { + return -1; + } + } + if (gfc->tag_spec.albumart != 0) { + free(gfc->tag_spec.albumart); + gfc->tag_spec.albumart = 0; + gfc->tag_spec.albumart_size = 0; + gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE; + } + if (size < 1 || mimetype == MIMETYPE_NONE) { + return 0; + } + gfc->tag_spec.albumart = lame_calloc(unsigned char, size); + if (gfc->tag_spec.albumart != 0) { + memcpy(gfc->tag_spec.albumart, image, size); + gfc->tag_spec.albumart_size = (unsigned int)size; + gfc->tag_spec.albumart_mimetype = mimetype; + gfc->tag_spec.flags |= CHANGED_FLAG; + id3tag_add_v2(gfp); + } + return 0; +} + +static unsigned char * +set_4_byte_value(unsigned char *bytes, uint32_t value) +{ + int i; + for (i = 3; i >= 0; --i) { + bytes[i] = value & 0xffUL; + value >>= 8; + } + return bytes + 4; +} + +static uint32_t +toID3v2TagId(char const *s) +{ + unsigned int i, x = 0; + if (s == 0) { + return 0; + } + for (i = 0; i < 4 && s[i] != 0; ++i) { + char const c = s[i]; + unsigned int const u = 0x0ff & c; + x <<= 8; + x |= u; + if (c < 'A' || 'Z' < c) { + if (c < '0' || '9' < c) { + return 0; + } + } + } + return x; +} + +static uint32_t +toID3v2TagId_ucs2(unsigned short const *s) +{ + unsigned int i, x = 0; + unsigned short bom = 0; + if (s == 0) { + return 0; + } + bom = s[0]; + if (hasUcs2ByteOrderMarker(bom)) { + ++s; + } + for (i = 0; i < 4 && s[i] != 0; ++i) { + unsigned short const c = toLittleEndian(bom, s[i]); + if (c < 'A' || 'Z' < c) { + if (c < '0' || '9' < c) { + return 0; + } + } + x <<= 8; + x |= c; + } + return x; +} + +#if 0 +static int +isNumericString(uint32_t frame_id) +{ + switch (frame_id) { + case ID_DATE: + case ID_TIME: + case ID_TPOS: + case ID_TRACK: + case ID_YEAR: + return 1; + } + return 0; +} +#endif + +static int +isMultiFrame(uint32_t frame_id) +{ + switch (frame_id) { + case ID_TXXX: + case ID_WXXX: + case ID_COMMENT: + case ID_SYLT: + case ID_APIC: + case ID_GEOB: + case ID_PCNT: + case ID_AENC: + case ID_LINK: + case ID_ENCR: + case ID_GRID: + case ID_PRIV: + return 1; + } + return 0; +} + +#if 0 +static int +isFullTextString(int frame_id) +{ + switch (frame_id) { + case ID_VSLT: + case ID_COMMENT: + return 1; + } + return 0; +} +#endif + +static FrameDataNode * +findNode(id3tag_spec const *tag, uint32_t frame_id, FrameDataNode const *last) +{ + FrameDataNode *node = last ? last->nxt : tag->v2_head; + while (node != 0) { + if (node->fid == frame_id) { + return node; + } + node = node->nxt; + } + return 0; +} + +static void +appendNode(id3tag_spec * tag, FrameDataNode * node) +{ + if (tag->v2_tail == 0 || tag->v2_head == 0) { + tag->v2_head = node; + tag->v2_tail = node; + } + else { + tag->v2_tail->nxt = node; + tag->v2_tail = node; + } +} + +static void +setLang(char *dst, char const *src) +{ + int i; + if (src == 0 || src[0] == 0) { + dst[0] = 'e'; + dst[1] = 'n'; + dst[2] = 'g'; + } + else { + for (i = 0; i < 3 && src && *src; ++i) { + dst[i] = src[i]; + } + for (; i < 3; ++i) { + dst[i] = ' '; + } + } +} + +static int +isSameLang(char const *l1, char const *l2) +{ + char d[3]; + int i; + setLang(d, l2); + for (i = 0; i < 3; ++i) { + char a = tolower(l1[i]); + char b = tolower(d[i]); + if (a < ' ') + a = ' '; + if (b < ' ') + b = ' '; + if (a != b) { + return 0; + } + } + return 1; +} + +static int +isSameDescriptor(FrameDataNode const *node, char const *dsc) +{ + size_t i; + if (node->dsc.enc == 1 && node->dsc.dim > 0) { + return 0; + } + for (i = 0; i < node->dsc.dim; ++i) { + if (!dsc || node->dsc.ptr.l[i] != dsc[i]) { + return 0; + } + } + return 1; +} + +static int +isSameDescriptorUcs2(FrameDataNode const *node, unsigned short const *dsc) +{ + size_t i; + if (node->dsc.enc != 1 && node->dsc.dim > 0) { + return 0; + } + for (i = 0; i < node->dsc.dim; ++i) { + if (!dsc || node->dsc.ptr.u[i] != dsc[i]) { + return 0; + } + } + return 1; +} + +static int +id3v2_add_ucs2(lame_t gfp, uint32_t frame_id, char const *lng, unsigned short const *desc, unsigned short const *text) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc != 0) { + FrameDataNode *node = findNode(&gfc->tag_spec, frame_id, 0); + char lang[4]; + setLang(lang, lng); + if (isMultiFrame(frame_id)) { + while (node) { + if (isSameLang(node->lng, lang)) { + if (isSameDescriptorUcs2(node, desc)) { + break; + } + } + node = findNode(&gfc->tag_spec, frame_id, node); + } + } + if (node == 0) { + node = lame_calloc(FrameDataNode, 1); + if (node == 0) { + return -254; /* memory problem */ + } + appendNode(&gfc->tag_spec, node); + } + node->fid = frame_id; + setLang(node->lng, lang); + node->dsc.dim = local_ucs2_strdup(&node->dsc.ptr.u, desc); + node->dsc.enc = 1; + node->txt.dim = local_ucs2_strdup(&node->txt.ptr.u, text); + node->txt.enc = 1; + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + return 0; + } + return -255; +} + +static int +id3v2_add_latin1(lame_t gfp, uint32_t frame_id, char const *lng, char const *desc, char const *text) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc != 0) { + FrameDataNode *node = findNode(&gfc->tag_spec, frame_id, 0); + char lang[4]; + setLang(lang, lng); + if (isMultiFrame(frame_id)) { + while (node) { + if (isSameLang(node->lng, lang)) { + if (isSameDescriptor(node, desc)) { + break; + } + } + node = findNode(&gfc->tag_spec, frame_id, node); + } + } + if (node == 0) { + node = lame_calloc(FrameDataNode, 1); + if (node == 0) { + return -254; /* memory problem */ + } + appendNode(&gfc->tag_spec, node); + } + node->fid = frame_id; + setLang(node->lng, lang); + node->dsc.dim = local_strdup(&node->dsc.ptr.l, desc); + node->dsc.enc = 0; + node->txt.dim = local_strdup(&node->txt.ptr.l, text); + node->txt.enc = 0; + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + return 0; + } + return -255; +} + +static char const* +id3v2_get_language(lame_t gfp) +{ + lame_internal_flags const* gfc = gfp ? gfp->internal_flags : 0; + if (gfc) return gfc->tag_spec.language; + return 0; +} + +static int +id3v2_add_ucs2_lng(lame_t gfp, uint32_t frame_id, unsigned short const *desc, unsigned short const *text) +{ + char const* lang = id3v2_get_language(gfp); + return id3v2_add_ucs2(gfp, frame_id, lang, desc, text); +} + +static int +id3v2_add_latin1_lng(lame_t gfp, uint32_t frame_id, char const *desc, char const *text) +{ + char const* lang = id3v2_get_language(gfp); + return id3v2_add_latin1(gfp, frame_id, lang, desc, text); +} + +static int +id3tag_set_userinfo_latin1(lame_t gfp, uint32_t id, char const *fieldvalue) +{ + char const separator = '='; + int rc = -7; + int a = local_char_pos(fieldvalue, separator); + if (a >= 0) { + char* dup = 0; + local_strdup(&dup, fieldvalue); + dup[a] = 0; + rc = id3v2_add_latin1_lng(gfp, id, dup, dup+a+1); + free(dup); + } + return rc; +} + +static int +id3tag_set_userinfo_ucs2(lame_t gfp, uint32_t id, unsigned short const *fieldvalue) +{ + unsigned short const separator = fromLatin1Char(fieldvalue,'='); + int rc = -7; + size_t b = local_ucs2_strlen(fieldvalue); + int a = local_ucs2_pos(fieldvalue, separator); + if (a >= 0) { + unsigned short* dsc = 0, *val = 0; + local_ucs2_substr(&dsc, fieldvalue, 0, a); + local_ucs2_substr(&val, fieldvalue, a+1, b); + rc = id3v2_add_ucs2_lng(gfp, id, dsc, val); + free(dsc); + free(val); + } + return rc; +} + +int +id3tag_set_textinfo_utf16(lame_t gfp, char const *id, unsigned short const *text) +{ + uint32_t const frame_id = toID3v2TagId(id); + if (frame_id == 0) { + return -1; + } + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (text == 0) { + return 0; + } + if (!hasUcs2ByteOrderMarker(text[0])) { + return -3; /* BOM missing */ + } + if (frame_id == ID_TXXX || frame_id == ID_WXXX || frame_id == ID_COMMENT) { + return id3tag_set_userinfo_ucs2(gfp, frame_id, text); + } + if (frame_id == ID_GENRE) { + return id3tag_set_genre_utf16(gfp, text); + } + if (frame_id == ID_PCST) { + return id3v2_add_ucs2_lng(gfp, frame_id, 0, text); + } + if (frame_id == ID_USER) { + return id3v2_add_ucs2_lng(gfp, frame_id, text, 0); + } + if (frame_id == ID_WFED) { + return id3v2_add_ucs2_lng(gfp, frame_id, text, 0); /* iTunes expects WFED to be a text frame */ + } + if (isFrameIdMatching(frame_id, FRAME_ID('T', 0, 0, 0)) + ||isFrameIdMatching(frame_id, FRAME_ID('W', 0, 0, 0))) { +#if 0 + if (isNumericString(frame_id)) { + return -2; /* must be Latin-1 encoded */ + } +#endif + return id3v2_add_ucs2_lng(gfp, frame_id, 0, text); + } + return -255; /* not supported by now */ +} + +extern int +id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text); + +int +id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text) +{ + return id3tag_set_textinfo_utf16(gfp, id, text); +} + +int +id3tag_set_textinfo_latin1(lame_t gfp, char const *id, char const *text) +{ + uint32_t const frame_id = toID3v2TagId(id); + if (frame_id == 0) { + return -1; + } + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (text == 0) { + return 0; + } + if (frame_id == ID_TXXX || frame_id == ID_WXXX || frame_id == ID_COMMENT) { + return id3tag_set_userinfo_latin1(gfp, frame_id, text); + } + if (frame_id == ID_GENRE) { + return id3tag_set_genre(gfp, text); + } + if (frame_id == ID_PCST) { + return id3v2_add_latin1_lng(gfp, frame_id, 0, text); + } + if (frame_id == ID_USER) { + return id3v2_add_latin1_lng(gfp, frame_id, text, 0); + } + if (frame_id == ID_WFED) { + return id3v2_add_latin1_lng(gfp, frame_id, text, 0); /* iTunes expects WFED to be a text frame */ + } + if (isFrameIdMatching(frame_id, FRAME_ID('T', 0, 0, 0)) + ||isFrameIdMatching(frame_id, FRAME_ID('W', 0, 0, 0))) { + return id3v2_add_latin1_lng(gfp, frame_id, 0, text); + } + return -255; /* not supported by now */ +} + + +int +id3tag_set_comment_latin1(lame_t gfp, char const *lang, char const *desc, char const *text) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3v2_add_latin1(gfp, ID_COMMENT, lang, desc, text); +} + + +int +id3tag_set_comment_utf16(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3v2_add_ucs2(gfp, ID_COMMENT, lang, desc, text); +} + +extern int +id3tag_set_comment_ucs2(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text); + + +int +id3tag_set_comment_ucs2(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3tag_set_comment_utf16(gfp, lang, desc, text); +} + + +void +id3tag_set_title(lame_t gfp, const char *title) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && title && *title) { + local_strdup(&gfc->tag_spec.title, title); + gfc->tag_spec.flags |= CHANGED_FLAG; + copyV1ToV2(gfp, ID_TITLE, title); + } +} + +void +id3tag_set_artist(lame_t gfp, const char *artist) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && artist && *artist) { + local_strdup(&gfc->tag_spec.artist, artist); + gfc->tag_spec.flags |= CHANGED_FLAG; + copyV1ToV2(gfp, ID_ARTIST, artist); + } +} + +void +id3tag_set_album(lame_t gfp, const char *album) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && album && *album) { + local_strdup(&gfc->tag_spec.album, album); + gfc->tag_spec.flags |= CHANGED_FLAG; + copyV1ToV2(gfp, ID_ALBUM, album); + } +} + +void +id3tag_set_year(lame_t gfp, const char *year) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && year && *year) { + int num = atoi(year); + if (num < 0) { + num = 0; + } + /* limit a year to 4 digits so it fits in a version 1 tag */ + if (num > 9999) { + num = 9999; + } + if (num) { + gfc->tag_spec.year = num; + gfc->tag_spec.flags |= CHANGED_FLAG; + } + copyV1ToV2(gfp, ID_YEAR, year); + } +} + +void +id3tag_set_comment(lame_t gfp, const char *comment) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && comment && *comment) { + local_strdup(&gfc->tag_spec.comment, comment); + gfc->tag_spec.flags |= CHANGED_FLAG; + { + uint32_t const flags = gfc->tag_spec.flags; + id3v2_add_latin1_lng(gfp, ID_COMMENT, "", comment); + gfc->tag_spec.flags = flags; + } + } +} + +int +id3tag_set_track(lame_t gfp, const char *track) +{ + char const *trackcount; + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + int ret = 0; + + if (gfc && track && *track) { + int num = atoi(track); + /* check for valid ID3v1 track number range */ + if (num < 1 || num > 255) { + num = 0; + ret = -1; /* track number out of ID3v1 range, ignored for ID3v1 */ + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + } + if (num) { + gfc->tag_spec.track_id3v1 = num; + gfc->tag_spec.flags |= CHANGED_FLAG; + } + /* Look for the total track count after a "/", same restrictions */ + trackcount = strchr(track, '/'); + if (trackcount && *trackcount) { + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + } + copyV1ToV2(gfp, ID_TRACK, track); + } + return ret; +} + +/* would use real "strcasecmp" but it isn't portable */ +static int +local_strcasecmp(const char *s1, const char *s2) +{ + unsigned char c1; + unsigned char c2; + do { + c1 = tolower(*s1); + c2 = tolower(*s2); + if (!c1) { + break; + } + ++s1; + ++s2; + } while (c1 == c2); + return c1 - c2; +} + + +static +const char* nextUpperAlpha(const char* p, char x) +{ + char c; + for(c = toupper(*p); *p != 0; c = toupper(*++p)) { + if ('A' <= c && c <= 'Z') { + if (c != x) { + return p; + } + } + } + return p; +} + + +static int +sloppyCompared(const char* p, const char* q) +{ + char cp, cq; + p = nextUpperAlpha(p, 0); + q = nextUpperAlpha(q, 0); + cp = toupper(*p); + cq = toupper(*q); + while (cp == cq) { + if (cp == 0) { + return 1; + } + if (p[1] == '.') { /* some abbrevation */ + while (*q && *q++ != ' ') { + } + } + p = nextUpperAlpha(p, cp); + q = nextUpperAlpha(q, cq); + cp = toupper(*p); + cq = toupper(*q); + } + return 0; +} + + +static int +sloppySearchGenre(const char *genre) +{ + int i; + for (i = 0; i < GENRE_NAME_COUNT; ++i) { + if (sloppyCompared(genre, genre_names[i])) { + return i; + } + } + return GENRE_NAME_COUNT; +} + + +static int +searchGenre(const char* genre) +{ + int i; + for (i = 0; i < GENRE_NAME_COUNT; ++i) { + if (!local_strcasecmp(genre, genre_names[i])) { + return i; + } + } + return GENRE_NAME_COUNT; +} + + +int +id3tag_set_genre(lame_t gfp, const char *genre) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + int ret = 0; + if (gfc && genre && *genre) { + int const num = lookupGenre(genre); + if (num == -1) return num; + gfc->tag_spec.flags |= CHANGED_FLAG; + if (num >= 0) { + gfc->tag_spec.genre_id3v1 = num; + genre = genre_names[num]; + } + else { + gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER; + gfc->tag_spec.flags |= ADD_V2_FLAG; + } + copyV1ToV2(gfp, ID_GENRE, genre); + } + return ret; +} + + +static size_t +sizeOfNode(FrameDataNode const *node) +{ + size_t n = 0; + if (node) { + n = 10; /* header size */ + n += 1; /* text encoding flag */ + switch (node->txt.enc) { + default: + case 0: + if (node->dsc.dim > 0) { + n += node->dsc.dim + 1; + } + n += node->txt.dim; + break; + case 1: + if (node->dsc.dim > 0) { + n += (node->dsc.dim+1) * 2; + } + n += node->txt.dim * 2; + break; + } + } + return n; +} + +static size_t +sizeOfCommentNode(FrameDataNode const *node) +{ + size_t n = 0; + if (node) { + n = 10; /* header size */ + n += 1; /* text encoding flag */ + n += 3; /* language */ + switch (node->dsc.enc) { + default: + case 0: + n += 1 + node->dsc.dim; + break; + case 1: + n += 2 + node->dsc.dim * 2; + break; + } + switch (node->txt.enc) { + default: + case 0: + n += node->txt.dim; + break; + case 1: + n += node->txt.dim * 2; + break; + } + } + return n; +} + +static size_t +sizeOfWxxxNode(FrameDataNode const *node) +{ + size_t n = 0; + if (node) { + n = 10; /* header size */ + if (node->dsc.dim > 0) { + n += 1; /* text encoding flag */ + switch (node->dsc.enc) { + default: + case 0: + n += 1 + node->dsc.dim; + break; + case 1: + n += 2 + node->dsc.dim * 2; + break; + } + } + if (node->txt.dim > 0) { + switch (node->txt.enc) { + default: + case 0: + n += node->txt.dim; + break; + case 1: + n += node->txt.dim - 1; /* UCS2 -> Latin1, skip BOM */ + break; + } + } + } + return n; +} + +static unsigned char * +writeChars(unsigned char *frame, char const *str, size_t n) +{ + while (n--) { + *frame++ = *str++; + } + return frame; +} + +static unsigned char * +writeUcs2s(unsigned char *frame, unsigned short const *str, size_t n) +{ + if (n > 0) { + unsigned short const bom = *str; + while (n--) { + unsigned short const c = toLittleEndian(bom, *str++); + *frame++ = 0x00ffu & c; + *frame++ = 0x00ffu & (c >> 8); + } + } + return frame; +} + +static unsigned char * +writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n) +{ + if (n > 0) { + unsigned short const bom = *str; + if (hasUcs2ByteOrderMarker(bom)) { + str++; n--; /* skip BOM */ + } + while (n--) { + unsigned short const c = toLittleEndian(bom, *str++); + if (c < 0x0020u || 0x00ffu < c) { + *frame++ = 0x0020; /* blank */ + } + else { + *frame++ = c; + } + } + } + return frame; +} + +static unsigned char * +set_frame_comment(unsigned char *frame, FrameDataNode const *node) +{ + size_t const n = sizeOfCommentNode(node); + if (n > 10) { + frame = set_4_byte_value(frame, node->fid); + frame = set_4_byte_value(frame, (uint32_t) (n - 10)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + /* encoding descriptor byte */ + *frame++ = node->txt.enc == 1 ? 1 : 0; + /* 3 bytes language */ + *frame++ = node->lng[0]; + *frame++ = node->lng[1]; + *frame++ = node->lng[2]; + /* descriptor with zero byte(s) separator */ + if (node->dsc.enc != 1) { + frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim); + *frame++ = 0; + } + else { + frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim); + *frame++ = 0; + *frame++ = 0; + } + /* comment full text */ + if (node->txt.enc != 1) { + frame = writeChars(frame, node->txt.ptr.l, node->txt.dim); + } + else { + frame = writeUcs2s(frame, node->txt.ptr.u, node->txt.dim); + } + } + return frame; +} + +static unsigned char * +set_frame_custom2(unsigned char *frame, FrameDataNode const *node) +{ + size_t const n = sizeOfNode(node); + if (n > 10) { + frame = set_4_byte_value(frame, node->fid); + frame = set_4_byte_value(frame, (unsigned long) (n - 10)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */ + *frame++ = node->txt.enc == 1 ? 1 : 0; + if (node->dsc.dim > 0) { + if (node->dsc.enc != 1) { + frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim); + *frame++ = 0; + } + else { + frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim); + *frame++ = 0; + *frame++ = 0; + } + } + if (node->txt.enc != 1) { + frame = writeChars(frame, node->txt.ptr.l, node->txt.dim); + } + else { + frame = writeUcs2s(frame, node->txt.ptr.u, node->txt.dim); + } + } + return frame; +} + +static unsigned char * +set_frame_wxxx(unsigned char *frame, FrameDataNode const *node) +{ + size_t const n = sizeOfWxxxNode(node); + if (n > 10) { + frame = set_4_byte_value(frame, node->fid); + frame = set_4_byte_value(frame, (unsigned long) (n - 10)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + if (node->dsc.dim > 0) { + /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */ + *frame++ = node->dsc.enc == 1 ? 1 : 0; + if (node->dsc.enc != 1) { + frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim); + *frame++ = 0; + } + else { + frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim); + *frame++ = 0; + *frame++ = 0; + } + } + if (node->txt.enc != 1) { + frame = writeChars(frame, node->txt.ptr.l, node->txt.dim); + } + else { + frame = writeLoBytes(frame, node->txt.ptr.u, node->txt.dim); + } + } + return frame; +} + +static unsigned char * +set_frame_apic(unsigned char *frame, const char *mimetype, const unsigned char *data, size_t size) +{ + /* ID3v2.3 standard APIC frame: + *
+ * Text encoding $xx + * MIME type $00 + * Picture type $xx + * Description $00 (00) + * Picture data + */ + if (mimetype && data && size) { + frame = set_4_byte_value(frame, FRAME_ID('A', 'P', 'I', 'C')); + frame = set_4_byte_value(frame, (unsigned long) (4 + strlen(mimetype) + size)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */ + *frame++ = 0; + /* copy mime_type */ + while (*mimetype) { + *frame++ = *mimetype++; + } + *frame++ = 0; + /* set picture type to 0 */ + *frame++ = 0; + /* empty description field */ + *frame++ = 0; + /* copy the image data */ + while (size--) { + *frame++ = *data++; + } + } + return frame; +} + +int +id3tag_set_fieldvalue(lame_t gfp, const char *fieldvalue) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (fieldvalue && *fieldvalue) { + if (strlen(fieldvalue) < 5 || fieldvalue[4] != '=') { + return -1; + } + return id3tag_set_textinfo_latin1(gfp, fieldvalue, &fieldvalue[5]); + } + return 0; +} + +int +id3tag_set_fieldvalue_utf16(lame_t gfp, const unsigned short *fieldvalue) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (fieldvalue && *fieldvalue) { + size_t dx = hasUcs2ByteOrderMarker(fieldvalue[0]); + unsigned short const separator = fromLatin1Char(fieldvalue, '='); + char fid[5] = {0,0,0,0,0}; + uint32_t const frame_id = toID3v2TagId_ucs2(fieldvalue); + if (local_ucs2_strlen(fieldvalue) < (5+dx) || fieldvalue[4+dx] != separator) { + return -1; + } + fid[0] = (frame_id >> 24) & 0x0ff; + fid[1] = (frame_id >> 16) & 0x0ff; + fid[2] = (frame_id >> 8) & 0x0ff; + fid[3] = frame_id & 0x0ff; + if (frame_id != 0) { + unsigned short* txt = 0; + int rc; + local_ucs2_substr(&txt, fieldvalue, dx+5, local_ucs2_strlen(fieldvalue)); + rc = id3tag_set_textinfo_utf16(gfp, fid, txt); + free(txt); + return rc; + } + } + return -1; +} + +extern int +id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue); + +int +id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3tag_set_fieldvalue_utf16(gfp, fieldvalue); +} + +size_t +lame_get_id3v2_tag(lame_t gfp, unsigned char *buffer, size_t size) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; + if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) { + return 0; + } +#if 0 + debug_tag_spec_flags(gfc, "lame_get_id3v2_tag"); +#endif + { + int usev2 = test_tag_spec_flags(gfc, ADD_V2_FLAG | V2_ONLY_FLAG); + /* calculate length of four fields which may not fit in verion 1 tag */ + size_t title_length = gfc->tag_spec.title ? strlen(gfc->tag_spec.title) : 0; + size_t artist_length = gfc->tag_spec.artist ? strlen(gfc->tag_spec.artist) : 0; + size_t album_length = gfc->tag_spec.album ? strlen(gfc->tag_spec.album) : 0; + size_t comment_length = gfc->tag_spec.comment ? strlen(gfc->tag_spec.comment) : 0; + /* write tag if explicitly requested or if fields overflow */ + if ((title_length > 30) + || (artist_length > 30) + || (album_length > 30) + || (comment_length > 30) + || (gfc->tag_spec.track_id3v1 && (comment_length > 28))) { + usev2 = 1; + } + if (usev2) { + size_t tag_size; + unsigned char *p; + size_t adjusted_tag_size; + const char *albumart_mime = NULL; + static const char *mime_jpeg = "image/jpeg"; + static const char *mime_png = "image/png"; + static const char *mime_gif = "image/gif"; + + if (gfp->num_samples != MAX_U_32_NUM) { + id3v2AddAudioDuration(gfp, gfp->num_samples); + } + + /* calulate size of tag starting with 10-byte tag header */ + tag_size = 10; + if (gfc->tag_spec.albumart && gfc->tag_spec.albumart_size) { + switch (gfc->tag_spec.albumart_mimetype) { + case MIMETYPE_JPEG: + albumart_mime = mime_jpeg; + break; + case MIMETYPE_PNG: + albumart_mime = mime_png; + break; + case MIMETYPE_GIF: + albumart_mime = mime_gif; + break; + } + if (albumart_mime) { + tag_size += 10 + 4 + strlen(albumart_mime) + gfc->tag_spec.albumart_size; + } + } + { + id3tag_spec *tag = &gfc->tag_spec; + if (tag->v2_head != 0) { + FrameDataNode *node; + for (node = tag->v2_head; node != 0; node = node->nxt) { + if (node->fid == ID_COMMENT || node->fid == ID_USER) { + tag_size += sizeOfCommentNode(node); + } + else if (isFrameIdMatching(node->fid, FRAME_ID('W',0,0,0))) { + tag_size += sizeOfWxxxNode(node); + } + else { + tag_size += sizeOfNode(node); + } + } + } + } + if (test_tag_spec_flags(gfc, PAD_V2_FLAG)) { + /* add some bytes of padding */ + tag_size += gfc->tag_spec.padding_size; + } + if (size < tag_size) { + return tag_size; + } + if (buffer == 0) { + return 0; + } + p = buffer; + /* set tag header starting with file identifier */ + *p++ = 'I'; + *p++ = 'D'; + *p++ = '3'; + /* set version number word */ + *p++ = 3; + *p++ = 0; + /* clear flags byte */ + *p++ = 0; + /* calculate and set tag size = total size - header size */ + adjusted_tag_size = tag_size - 10; + /* encode adjusted size into four bytes where most significant + * bit is clear in each byte, for 28-bit total */ + *p++ = (unsigned char) ((adjusted_tag_size >> 21) & 0x7fu); + *p++ = (unsigned char) ((adjusted_tag_size >> 14) & 0x7fu); + *p++ = (unsigned char) ((adjusted_tag_size >> 7) & 0x7fu); + *p++ = (unsigned char) (adjusted_tag_size & 0x7fu); + + /* + * NOTE: The remainder of the tag (frames and padding, if any) + * are not "unsynchronized" to prevent false MPEG audio headers + * from appearing in the bitstream. Why? Well, most players + * and utilities know how to skip the ID3 version 2 tag by now + * even if they don't read its contents, and it's actually + * very unlikely that such a false "sync" pattern would occur + * in just the simple text frames added here. + */ + + /* set each frame in tag */ + { + id3tag_spec *tag = &gfc->tag_spec; + if (tag->v2_head != 0) { + FrameDataNode *node; + for (node = tag->v2_head; node != 0; node = node->nxt) { + if (node->fid == ID_COMMENT || node->fid == ID_USER) { + p = set_frame_comment(p, node); + } + else if (isFrameIdMatching(node->fid,FRAME_ID('W',0,0,0))) { + p = set_frame_wxxx(p, node); + } + else { + p = set_frame_custom2(p, node); + } + } + } + } + if (albumart_mime) { + p = set_frame_apic(p, albumart_mime, gfc->tag_spec.albumart, + gfc->tag_spec.albumart_size); + } + /* clear any padding bytes */ + memset(p, 0, tag_size - (p - buffer)); + return tag_size; + } + } + return 0; +} + +int +id3tag_write_v2(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; +#if 0 + debug_tag_spec_flags(gfc, "write v2"); +#endif + if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) { + return 0; + } + if (test_tag_spec_flags(gfc, CHANGED_FLAG)) { + unsigned char *tag = 0; + size_t tag_size, n; + + n = lame_get_id3v2_tag(gfp, 0, 0); + tag = lame_calloc(unsigned char, n); + if (tag == 0) { + return -1; + } + tag_size = lame_get_id3v2_tag(gfp, tag, n); + if (tag_size > n) { + free(tag); + return -1; + } + else { + size_t i; + /* write tag directly into bitstream at current position */ + for (i = 0; i < tag_size; ++i) { + add_dummy_byte(gfc, tag[i], 1); + } + } + free(tag); + return (int) tag_size; /* ok, tag should not exceed 2GB */ + } + return 0; +} + +static unsigned char * +set_text_field(unsigned char *field, const char *text, size_t size, int pad) +{ + while (size--) { + if (text && *text) { + *field++ = *text++; + } + else { + *field++ = pad; + } + } + return field; +} + +size_t +lame_get_id3v1_tag(lame_t gfp, unsigned char *buffer, size_t size) +{ + size_t const tag_size = 128; + lame_internal_flags *gfc; + + if (gfp == 0) { + return 0; + } + if (size < tag_size) { + return tag_size; + } + gfc = gfp->internal_flags; + if (gfc == 0) { + return 0; + } + if (buffer == 0) { + return 0; + } + if (test_tag_spec_flags(gfc, V2_ONLY_FLAG)) { + return 0; + } + if (test_tag_spec_flags(gfc, CHANGED_FLAG)) { + unsigned char *p = buffer; + int pad = test_tag_spec_flags(gfc, SPACE_V1_FLAG) ? ' ' : 0; + char year[5]; + + /* set tag identifier */ + *p++ = 'T'; + *p++ = 'A'; + *p++ = 'G'; + /* set each field in tag */ + p = set_text_field(p, gfc->tag_spec.title, 30, pad); + p = set_text_field(p, gfc->tag_spec.artist, 30, pad); + p = set_text_field(p, gfc->tag_spec.album, 30, pad); + sprintf(year, "%d", gfc->tag_spec.year); + p = set_text_field(p, gfc->tag_spec.year ? year : NULL, 4, pad); + /* limit comment field to 28 bytes if a track is specified */ + p = set_text_field(p, gfc->tag_spec.comment, gfc->tag_spec.track_id3v1 ? 28 : 30, pad); + if (gfc->tag_spec.track_id3v1) { + /* clear the next byte to indicate a version 1.1 tag */ + *p++ = 0; + *p++ = gfc->tag_spec.track_id3v1; + } + *p++ = gfc->tag_spec.genre_id3v1; + return tag_size; + } + return 0; +} + +int +id3tag_write_v1(lame_t gfp) +{ + lame_internal_flags* gfc = 0; + size_t i, n, m; + unsigned char tag[128]; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; + + m = sizeof(tag); + n = lame_get_id3v1_tag(gfp, tag, m); + if (n > m) { + return 0; + } + /* write tag directly into bitstream at current position */ + for (i = 0; i < n; ++i) { + add_dummy_byte(gfc, tag[i], 1); + } + return (int) n; /* ok, tag has fixed size of 128 bytes, well below 2GB */ +} diff --git a/pkg/lame/clame/id3tag.h b/pkg/lame/clame/id3tag.h new file mode 100644 index 0000000..9cd9ad9 --- /dev/null +++ b/pkg/lame/clame/id3tag.h @@ -0,0 +1,64 @@ + +#ifndef LAME_ID3_H +#define LAME_ID3_H + + +#define CHANGED_FLAG (1U << 0) +#define ADD_V2_FLAG (1U << 1) +#define V1_ONLY_FLAG (1U << 2) +#define V2_ONLY_FLAG (1U << 3) +#define SPACE_V1_FLAG (1U << 4) +#define PAD_V2_FLAG (1U << 5) + +enum { + MIMETYPE_NONE = 0, + MIMETYPE_JPEG, + MIMETYPE_PNG, + MIMETYPE_GIF +}; + +typedef struct FrameDataNode { + struct FrameDataNode *nxt; + uint32_t fid; /* Frame Identifier */ + char lng[4]; /* 3-character language descriptor */ + struct { + union { + char *l; /* ptr to Latin-1 chars */ + unsigned short *u; /* ptr to UCS-2 text */ + unsigned char *b; /* ptr to raw bytes */ + } ptr; + size_t dim; + int enc; /* 0:Latin-1, 1:UCS-2, 2:RAW */ + } dsc , txt; +} FrameDataNode; + + +typedef struct id3tag_spec { + /* private data members */ + unsigned int flags; + int year; + char *title; + char *artist; + char *album; + char *comment; + int track_id3v1; + int genre_id3v1; + unsigned char *albumart; + unsigned int albumart_size; + unsigned int padding_size; + int albumart_mimetype; + char language[4]; /* the language of the frame's content, according to ISO-639-2 */ + FrameDataNode *v2_head, *v2_tail; +} id3tag_spec; + + +/* write tag into stream at current position */ +extern int id3tag_write_v2(lame_global_flags * gfp); +extern int id3tag_write_v1(lame_global_flags * gfp); +/* + * NOTE: A version 2 tag will NOT be added unless one of the text fields won't + * fit in a version 1 tag (e.g. the title string is longer than 30 characters), + * or the "id3tag_add_v2" or "id3tag_v2_only" functions are used. + */ + +#endif diff --git a/pkg/lame/clame/l3side.h b/pkg/lame/clame/l3side.h new file mode 100644 index 0000000..f65bbed --- /dev/null +++ b/pkg/lame/clame/l3side.h @@ -0,0 +1,95 @@ +/* + * Layer 3 side include file + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_L3SIDE_H +#define LAME_L3SIDE_H + +/* max scalefactor band, max(SBMAX_l, SBMAX_s*3, (SBMAX_s-3)*3+8) */ +#define SFBMAX (SBMAX_s*3) + +/* Layer III side information. */ +typedef struct { + int l[1 + SBMAX_l]; + int s[1 + SBMAX_s]; + int psfb21[1 + PSFB21]; + int psfb12[1 + PSFB12]; +} scalefac_struct; + + +typedef struct { + FLOAT l[SBMAX_l]; + FLOAT s[SBMAX_s][3]; +} III_psy_xmin; + +typedef struct { + III_psy_xmin thm; + III_psy_xmin en; +} III_psy_ratio; + +typedef struct { + FLOAT xr[576]; + int l3_enc[576]; + int scalefac[SFBMAX]; + FLOAT xrpow_max; + + int part2_3_length; + int big_values; + int count1; + int global_gain; + int scalefac_compress; + int block_type; + int mixed_block_flag; + int table_select[3]; + int subblock_gain[3 + 1]; + int region0_count; + int region1_count; + int preflag; + int scalefac_scale; + int count1table_select; + + int part2_length; + int sfb_lmax; + int sfb_smin; + int psy_lmax; + int sfbmax; + int psymax; + int sfbdivide; + int width[SFBMAX]; + int window[SFBMAX]; + int count1bits; + /* added for LSF */ + const int *sfb_partition_table; + int slen[4]; + + int max_nonzero_coeff; + char energy_above_cutoff[SFBMAX]; +} gr_info; + +typedef struct { + gr_info tt[2][2]; + int main_data_begin; + int private_bits; + int resvDrain_pre; + int resvDrain_post; + int scfsi[2][4]; +} III_side_info_t; + +#endif diff --git a/pkg/lame/clame/lame-analysis.h b/pkg/lame/clame/lame-analysis.h new file mode 100644 index 0000000..5055a60 --- /dev/null +++ b/pkg/lame/clame/lame-analysis.h @@ -0,0 +1,96 @@ +/* + * GTK plotting routines source file + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_GTKANAL_H +#define LAME_GTKANAL_H + + +#define READ_AHEAD 40 /* number of frames to read ahead */ +#define MAXMPGLAG READ_AHEAD /* if the mpg123 lag becomes bigger than this + we have to stop */ +#define NUMBACK 6 /* number of frames we can back up */ +#define NUMPINFO (NUMBACK+READ_AHEAD+1) + + + +struct plotting_data { + int frameNum; /* current frame number */ + int frameNum123; + int num_samples; /* number of pcm samples read for this frame */ + double frametime; /* starting time of frame, in seconds */ + double pcmdata[2][1600]; + double pcmdata2[2][1152 + 1152 - DECDELAY]; + double xr[2][2][576]; + double mpg123xr[2][2][576]; + double ms_ratio[2]; + double ms_ener_ratio[2]; + + /* L,R, M and S values */ + double energy_save[4][BLKSIZE]; /* psymodel is one ahead */ + double energy[2][4][BLKSIZE]; + double pe[2][4]; + double thr[2][4][SBMAX_l]; + double en[2][4][SBMAX_l]; + double thr_s[2][4][3 * SBMAX_s]; + double en_s[2][4][3 * SBMAX_s]; + double ers_save[4]; /* psymodel is one ahead */ + double ers[2][4]; + + double sfb[2][2][SBMAX_l]; + double sfb_s[2][2][3 * SBMAX_s]; + double LAMEsfb[2][2][SBMAX_l]; + double LAMEsfb_s[2][2][3 * SBMAX_s]; + + int LAMEqss[2][2]; + int qss[2][2]; + int big_values[2][2]; + int sub_gain[2][2][3]; + + double xfsf[2][2][SBMAX_l]; + double xfsf_s[2][2][3 * SBMAX_s]; + + int over[2][2]; + double tot_noise[2][2]; + double max_noise[2][2]; + double over_noise[2][2]; + int over_SSD[2][2]; + int blocktype[2][2]; + int scalefac_scale[2][2]; + int preflag[2][2]; + int mpg123blocktype[2][2]; + int mixed[2][2]; + int mainbits[2][2]; + int sfbits[2][2]; + int LAMEmainbits[2][2]; + int LAMEsfbits[2][2]; + int framesize, stereo, js, ms_stereo, i_stereo, emph, bitrate, sampfreq, maindata; + int crc, padding; + int scfsi[2], mean_bits, resvsize; + int totbits; +}; +#ifndef plotting_data_defined +#define plotting_data_defined +typedef struct plotting_data plotting_data; +#endif +#if 0 +extern plotting_data *pinfo; +#endif +#endif diff --git a/pkg/lame/clame/lame.c b/pkg/lame/clame/lame.c new file mode 100644 index 0000000..cb82225 --- /dev/null +++ b/pkg/lame/clame/lame.c @@ -0,0 +1,2665 @@ +/* -*- mode: C; mode: fold -*- */ +/* + * LAME MP3 encoding engine + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2000-2005 Takehiro Tominaga + * Copyright (c) 2000-2017 Robert Hegemann + * Copyright (c) 2000-2005 Gabriel Bouvigne + * Copyright (c) 2000-2004 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: lame.c,v 1.377 2017/09/26 12:14:02 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" + +#include "encoder.h" +#include "util.h" +#include "lame_global_flags.h" +#include "gain_analysis.h" +#include "bitstream.h" +#include "quantize_pvt.h" +#include "set_get.h" +#include "quantize.h" +#include "psymodel.h" +#include "version.h" +#include "VbrTag.h" +#include "tables.h" + + +#if defined(__FreeBSD__) && !defined(__alpha__) +#include +#endif +#ifdef __riscos__ +#include "asmstuff.h" +#endif + +#ifdef __sun__ +/* woraround for SunOS 4.x, it has SEEK_* defined here */ +#include +#endif + + +#define LAME_DEFAULT_QUALITY 3 + + + +int +is_lame_global_flags_valid(const lame_global_flags * gfp) +{ + if (gfp == NULL) + return 0; + if (gfp->class_id != LAME_ID) + return 0; + return 1; +} + + +int +is_lame_internal_flags_valid(const lame_internal_flags * gfc) +{ + if (gfc == NULL) + return 0; + if (gfc->class_id != LAME_ID) + return 0; + if (gfc->lame_init_params_successful <=0) + return 0; + return 1; +} + + + +static FLOAT +filter_coef(FLOAT x) +{ + if (x > 1.0) + return 0.0; + if (x <= 0.0) + return 1.0; + + return cos(PI / 2 * x); +} + +static void +lame_init_params_ppflt(lame_internal_flags * gfc) +{ + SessionConfig_t *const cfg = &gfc->cfg; + + /***************************************************************/ + /* compute info needed for polyphase filter (filter type==0, default) */ + /***************************************************************/ + + int band, maxband, minband; + FLOAT freq; + int lowpass_band = 32; + int highpass_band = -1; + + if (cfg->lowpass1 > 0) { + minband = 999; + for (band = 0; band <= 31; band++) { + freq = band / 31.0; + /* this band and above will be zeroed: */ + if (freq >= cfg->lowpass2) { + lowpass_band = Min(lowpass_band, band); + } + if (cfg->lowpass1 < freq && freq < cfg->lowpass2) { + minband = Min(minband, band); + } + } + + /* compute the *actual* transition band implemented by + * the polyphase filter */ + if (minband == 999) { + cfg->lowpass1 = (lowpass_band - .75) / 31.0; + } + else { + cfg->lowpass1 = (minband - .75) / 31.0; + } + cfg->lowpass2 = lowpass_band / 31.0; + } + + /* make sure highpass filter is within 90% of what the effective + * highpass frequency will be */ + if (cfg->highpass2 > 0) { + if (cfg->highpass2 < .9 * (.75 / 31.0)) { + cfg->highpass1 = 0; + cfg->highpass2 = 0; + MSGF(gfc, "Warning: highpass filter disabled. " "highpass frequency too small\n"); + } + } + + if (cfg->highpass2 > 0) { + maxband = -1; + for (band = 0; band <= 31; band++) { + freq = band / 31.0; + /* this band and below will be zereod */ + if (freq <= cfg->highpass1) { + highpass_band = Max(highpass_band, band); + } + if (cfg->highpass1 < freq && freq < cfg->highpass2) { + maxband = Max(maxband, band); + } + } + /* compute the *actual* transition band implemented by + * the polyphase filter */ + cfg->highpass1 = highpass_band / 31.0; + if (maxband == -1) { + cfg->highpass2 = (highpass_band + .75) / 31.0; + } + else { + cfg->highpass2 = (maxband + .75) / 31.0; + } + } + + for (band = 0; band < 32; band++) { + FLOAT fc1, fc2; + freq = band / 31.0f; + if (cfg->highpass2 > cfg->highpass1) { + fc1 = filter_coef((cfg->highpass2 - freq) / (cfg->highpass2 - cfg->highpass1 + 1e-20)); + } + else { + fc1 = 1.0f; + } + if (cfg->lowpass2 > cfg->lowpass1) { + fc2 = filter_coef((freq - cfg->lowpass1) / (cfg->lowpass2 - cfg->lowpass1 + 1e-20)); + } + else { + fc2 = 1.0f; + } + gfc->sv_enc.amp_filter[band] = fc1 * fc2; + } +} + + +static void +optimum_bandwidth(double *const lowerlimit, double *const upperlimit, const unsigned bitrate) +{ +/* + * Input: + * bitrate total bitrate in kbps + * + * Output: + * lowerlimit: best lowpass frequency limit for input filter in Hz + * upperlimit: best highpass frequency limit for input filter in Hz + */ + int table_index; + + typedef struct { + int bitrate; /* only indicative value */ + int lowpass; + } band_pass_t; + + const band_pass_t freq_map[] = { + {8, 2000}, + {16, 3700}, + {24, 3900}, + {32, 5500}, + {40, 7000}, + {48, 7500}, + {56, 10000}, + {64, 11000}, + {80, 13500}, + {96, 15100}, + {112, 15600}, + {128, 17000}, + {160, 17500}, + {192, 18600}, + {224, 19400}, + {256, 19700}, + {320, 20500} + }; + + + table_index = nearestBitrateFullIndex(bitrate); + + (void) freq_map[table_index].bitrate; + *lowerlimit = freq_map[table_index].lowpass; + + +/* + * Now we try to choose a good high pass filtering frequency. + * This value is currently not used. + * For fu < 16 kHz: sqrt(fu*fl) = 560 Hz + * For fu = 18 kHz: no high pass filtering + * This gives: + * + * 2 kHz => 160 Hz + * 3 kHz => 107 Hz + * 4 kHz => 80 Hz + * 8 kHz => 40 Hz + * 16 kHz => 20 Hz + * 17 kHz => 10 Hz + * 18 kHz => 0 Hz + * + * These are ad hoc values and these can be optimized if a high pass is available. + */ +/* if (f_low <= 16000) + f_high = 16000. * 20. / f_low; + else if (f_low <= 18000) + f_high = 180. - 0.01 * f_low; + else + f_high = 0.;*/ + + /* + * When we sometimes have a good highpass filter, we can add the highpass + * frequency to the lowpass frequency + */ + + /*if (upperlimit != NULL) + *upperlimit = f_high;*/ + (void) upperlimit; +} + + +static int +optimum_samplefreq(int lowpassfreq, int input_samplefreq) +{ +/* + * Rules: + * - if possible, sfb21 should NOT be used + * + */ + int suggested_samplefreq = 44100; + + if (input_samplefreq >= 48000) + suggested_samplefreq = 48000; + else if (input_samplefreq >= 44100) + suggested_samplefreq = 44100; + else if (input_samplefreq >= 32000) + suggested_samplefreq = 32000; + else if (input_samplefreq >= 24000) + suggested_samplefreq = 24000; + else if (input_samplefreq >= 22050) + suggested_samplefreq = 22050; + else if (input_samplefreq >= 16000) + suggested_samplefreq = 16000; + else if (input_samplefreq >= 12000) + suggested_samplefreq = 12000; + else if (input_samplefreq >= 11025) + suggested_samplefreq = 11025; + else if (input_samplefreq >= 8000) + suggested_samplefreq = 8000; + + if (lowpassfreq == -1) + return suggested_samplefreq; + + if (lowpassfreq <= 15960) + suggested_samplefreq = 44100; + if (lowpassfreq <= 15250) + suggested_samplefreq = 32000; + if (lowpassfreq <= 11220) + suggested_samplefreq = 24000; + if (lowpassfreq <= 9970) + suggested_samplefreq = 22050; + if (lowpassfreq <= 7230) + suggested_samplefreq = 16000; + if (lowpassfreq <= 5420) + suggested_samplefreq = 12000; + if (lowpassfreq <= 4510) + suggested_samplefreq = 11025; + if (lowpassfreq <= 3970) + suggested_samplefreq = 8000; + + if (input_samplefreq < suggested_samplefreq) { + /* choose a valid MPEG sample frequency above the input sample frequency + to avoid SFB21/12 bitrate bloat + rh 061115 + */ + if (input_samplefreq > 44100) { + return 48000; + } + if (input_samplefreq > 32000) { + return 44100; + } + if (input_samplefreq > 24000) { + return 32000; + } + if (input_samplefreq > 22050) { + return 24000; + } + if (input_samplefreq > 16000) { + return 22050; + } + if (input_samplefreq > 12000) { + return 16000; + } + if (input_samplefreq > 11025) { + return 12000; + } + if (input_samplefreq > 8000) { + return 11025; + } + return 8000; + } + return suggested_samplefreq; +} + + + + + +/* set internal feature flags. USER should not access these since + * some combinations will produce strange results */ +static void +lame_init_qval(lame_global_flags * gfp) +{ + lame_internal_flags *const gfc = gfp->internal_flags; + SessionConfig_t *const cfg = &gfc->cfg; + + switch (gfp->quality) { + default: + case 9: /* no psymodel, no noise shaping */ + cfg->noise_shaping = 0; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + break; + + case 8: + gfp->quality = 7; + /*lint --fallthrough */ + case 7: /* use psymodel (for short block and m/s switching), but no noise shapping */ + cfg->noise_shaping = 0; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + if (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh) { + cfg->full_outer_loop = -1; + } + break; + + case 6: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + break; + + case 5: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + break; + + case 4: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; + cfg->full_outer_loop = 0; + break; + + case 3: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 1; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; + cfg->full_outer_loop = 0; + break; + + case 2: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + if (gfc->sv_qnt.substep_shaping == 0) + gfc->sv_qnt.substep_shaping = 2; + cfg->noise_shaping_amp = 1; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; /* inner loop */ + cfg->full_outer_loop = 0; + break; + + case 1: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + if (gfc->sv_qnt.substep_shaping == 0) + gfc->sv_qnt.substep_shaping = 2; + cfg->noise_shaping_amp = 2; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; + cfg->full_outer_loop = 0; + break; + + case 0: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + if (gfc->sv_qnt.substep_shaping == 0) + gfc->sv_qnt.substep_shaping = 2; + cfg->noise_shaping_amp = 2; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; /*type 2 disabled because of it slowness, + in favor of full outer loop search */ + cfg->full_outer_loop = 1; + break; + } + +} + + + +static double +linear_int(double a, double b, double m) +{ + return a + m * (b - a); +} + + + +/******************************************************************** + * initialize internal params based on data in gf + * (globalflags struct filled in by calling program) + * + * OUTLINE: + * + * We first have some complex code to determine bitrate, + * output samplerate and mode. It is complicated by the fact + * that we allow the user to set some or all of these parameters, + * and need to determine best possible values for the rest of them: + * + * 1. set some CPU related flags + * 2. check if we are mono->mono, stereo->mono or stereo->stereo + * 3. compute bitrate and output samplerate: + * user may have set compression ratio + * user may have set a bitrate + * user may have set a output samplerate + * 4. set some options which depend on output samplerate + * 5. compute the actual compression ratio + * 6. set mode based on compression ratio + * + * The remaining code is much simpler - it just sets options + * based on the mode & compression ratio: + * + * set allow_diff_short based on mode + * select lowpass filter based on compression ratio & mode + * set the bitrate index, and min/max bitrates for VBR modes + * disable VBR tag if it is not appropriate + * initialize the bitstream + * initialize scalefac_band data + * set sideinfo_len (based on channels, CRC, out_samplerate) + * write an id3v2 tag into the bitstream + * write VBR tag into the bitstream + * set mpeg1/2 flag + * estimate the number of frames (based on a lot of data) + * + * now we set more flags: + * nspsytune: + * see code + * VBR modes + * see code + * CBR/ABR + * see code + * + * Finally, we set the algorithm flags based on the gfp->quality value + * lame_init_qval(gfp); + * + ********************************************************************/ +int +lame_init_params(lame_global_flags * gfp) +{ + + int i; + int j; + lame_internal_flags *gfc; + SessionConfig_t *cfg; + + if (!is_lame_global_flags_valid(gfp)) + return -1; + + gfc = gfp->internal_flags; + if (gfc == 0) + return -1; + + if (is_lame_internal_flags_valid(gfc)) + return -1; /* already initialized */ + + /* start updating lame internal flags */ + gfc->class_id = LAME_ID; + gfc->lame_init_params_successful = 0; /* will be set to one, when we get through until the end */ + + if (gfp->samplerate_in < 1) + return -1; /* input sample rate makes no sense */ + if (gfp->num_channels < 1 || 2 < gfp->num_channels) + return -1; /* number of input channels makes no sense */ + if (gfp->samplerate_out != 0) { + int v=0; + if (SmpFrqIndex(gfp->samplerate_out, &v) < 0) + return -1; /* output sample rate makes no sense */ + } + + cfg = &gfc->cfg; + + cfg->enforce_min_bitrate = gfp->VBR_hard_min; + cfg->analysis = gfp->analysis; + if (cfg->analysis) + gfp->write_lame_tag = 0; + + /* some file options not allowed if output is: not specified or stdout */ + if (gfc->pinfo != NULL) + gfp->write_lame_tag = 0; /* disable Xing VBR tag */ + + /* report functions */ + gfc->report_msg = gfp->report.msgf; + gfc->report_dbg = gfp->report.debugf; + gfc->report_err = gfp->report.errorf; + + if (gfp->asm_optimizations.amd3dnow) + gfc->CPU_features.AMD_3DNow = has_3DNow(); + else + gfc->CPU_features.AMD_3DNow = 0; + + if (gfp->asm_optimizations.mmx) + gfc->CPU_features.MMX = has_MMX(); + else + gfc->CPU_features.MMX = 0; + + if (gfp->asm_optimizations.sse) { + gfc->CPU_features.SSE = has_SSE(); + gfc->CPU_features.SSE2 = has_SSE2(); + } + else { + gfc->CPU_features.SSE = 0; + gfc->CPU_features.SSE2 = 0; + } + + + cfg->vbr = gfp->VBR; + cfg->error_protection = gfp->error_protection; + cfg->copyright = gfp->copyright; + cfg->original = gfp->original; + cfg->extension = gfp->extension; + cfg->emphasis = gfp->emphasis; + + cfg->channels_in = gfp->num_channels; + if (cfg->channels_in == 1) + gfp->mode = MONO; + cfg->channels_out = (gfp->mode == MONO) ? 1 : 2; + if (gfp->mode != JOINT_STEREO) + gfp->force_ms = 0; /* forced mid/side stereo for j-stereo only */ + cfg->force_ms = gfp->force_ms; + + if (cfg->vbr == vbr_off && gfp->VBR_mean_bitrate_kbps != 128 && gfp->brate == 0) + gfp->brate = gfp->VBR_mean_bitrate_kbps; + + switch (cfg->vbr) { + case vbr_off: + case vbr_mtrh: + case vbr_mt: + /* these modes can handle free format condition */ + break; + default: + gfp->free_format = 0; /* mode can't be mixed with free format */ + break; + } + + cfg->free_format = gfp->free_format; + + if (cfg->vbr == vbr_off && gfp->brate == 0) { + /* no bitrate or compression ratio specified, use 11.025 */ + if (EQ(gfp->compression_ratio, 0)) + gfp->compression_ratio = 11.025; /* rate to compress a CD down to exactly 128000 bps */ + } + + /* find bitrate if user specify a compression ratio */ + if (cfg->vbr == vbr_off && gfp->compression_ratio > 0) { + + if (gfp->samplerate_out == 0) + gfp->samplerate_out = map2MP3Frequency((int) (0.97 * gfp->samplerate_in)); /* round up with a margin of 3% */ + + /* choose a bitrate for the output samplerate which achieves + * specified compression ratio + */ + gfp->brate = gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->compression_ratio); + + /* we need the version for the bitrate table look up */ + cfg->samplerate_index = SmpFrqIndex(gfp->samplerate_out, &cfg->version); + assert(cfg->samplerate_index >=0); + + if (!cfg->free_format) /* for non Free Format find the nearest allowed bitrate */ + gfp->brate = FindNearestBitrate(gfp->brate, cfg->version, gfp->samplerate_out); + } + if (gfp->samplerate_out) { + if (gfp->samplerate_out < 16000) { + gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 8); + gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 64); + } + else if (gfp->samplerate_out < 32000) { + gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 8); + gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 160); + } + else { + gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 32); + gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 320); + } + } + /* WORK IN PROGRESS */ + /* mapping VBR scale to internal VBR quality settings */ + if (gfp->samplerate_out == 0 && (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh)) { + float const qval = gfp->VBR_q + gfp->VBR_q_frac; + struct q_map { int sr_a; float qa, qb, ta, tb; int lp; }; + struct q_map const m[9] + = { {48000, 0.0,6.5, 0.0,6.5, 23700} + , {44100, 0.0,6.5, 0.0,6.5, 21780} + , {32000, 6.5,8.0, 5.2,6.5, 15800} + , {24000, 8.0,8.5, 5.2,6.0, 11850} + , {22050, 8.5,9.01, 5.2,6.5, 10892} + , {16000, 9.01,9.4, 4.9,6.5, 7903} + , {12000, 9.4,9.6, 4.5,6.0, 5928} + , {11025, 9.6,9.9, 5.1,6.5, 5446} + , { 8000, 9.9,10., 4.9,6.5, 3952} + }; + for (i = 2; i < 9; ++i) { + if (gfp->samplerate_in == m[i].sr_a) { + if (qval < m[i].qa) { + double d = qval / m[i].qa; + d = d * m[i].ta; + gfp->VBR_q = (int)d; + gfp->VBR_q_frac = d - gfp->VBR_q; + } + } + if (gfp->samplerate_in >= m[i].sr_a) { + if (m[i].qa <= qval && qval < m[i].qb) { + float const q_ = m[i].qb-m[i].qa; + float const t_ = m[i].tb-m[i].ta; + double d = m[i].ta + t_ * (qval-m[i].qa) / q_; + gfp->VBR_q = (int)d; + gfp->VBR_q_frac = d - gfp->VBR_q; + gfp->samplerate_out = m[i].sr_a; + if (gfp->lowpassfreq == 0) { + gfp->lowpassfreq = -1; + } + break; + } + } + } + } + + /****************************************************************/ + /* if a filter has not been enabled, see if we should add one: */ + /****************************************************************/ + if (gfp->lowpassfreq == 0) { + double lowpass = 16000; + double highpass; + + switch (cfg->vbr) { + case vbr_off:{ + optimum_bandwidth(&lowpass, &highpass, gfp->brate); + break; + } + case vbr_abr:{ + optimum_bandwidth(&lowpass, &highpass, gfp->VBR_mean_bitrate_kbps); + break; + } + case vbr_rh:{ + int const x[11] = { + 19500, 19000, 18600, 18000, 17500, 16000, 15600, 14900, 12500, 10000, 3950 + }; + if (0 <= gfp->VBR_q && gfp->VBR_q <= 9) { + double a = x[gfp->VBR_q], b = x[gfp->VBR_q + 1], m = gfp->VBR_q_frac; + lowpass = linear_int(a, b, m); + } + else { + lowpass = 19500; + } + break; + } + case vbr_mtrh: + case vbr_mt:{ + int const x[11] = { + 24000, 19500, 18500, 18000, 17500, 17000, 16500, 15600, 15200, 7230, 3950 + }; + if (0 <= gfp->VBR_q && gfp->VBR_q <= 9) { + double a = x[gfp->VBR_q], b = x[gfp->VBR_q + 1], m = gfp->VBR_q_frac; + lowpass = linear_int(a, b, m); + } + else { + lowpass = 21500; + } + break; + } + default:{ + int const x[11] = { + 19500, 19000, 18500, 18000, 17500, 16500, 15500, 14500, 12500, 9500, 3950 + }; + if (0 <= gfp->VBR_q && gfp->VBR_q <= 9) { + double a = x[gfp->VBR_q], b = x[gfp->VBR_q + 1], m = gfp->VBR_q_frac; + lowpass = linear_int(a, b, m); + } + else { + lowpass = 19500; + } + } + } + + if (gfp->mode == MONO && (cfg->vbr == vbr_off || cfg->vbr == vbr_abr)) + lowpass *= 1.5; + + gfp->lowpassfreq = lowpass; + } + + if (gfp->samplerate_out == 0) { + if (2 * gfp->lowpassfreq > gfp->samplerate_in) { + gfp->lowpassfreq = gfp->samplerate_in / 2; + } + gfp->samplerate_out = optimum_samplefreq((int) gfp->lowpassfreq, gfp->samplerate_in); + } + if (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh) { + gfp->lowpassfreq = Min(24000, gfp->lowpassfreq); + } + else { + gfp->lowpassfreq = Min(20500, gfp->lowpassfreq); + } + gfp->lowpassfreq = Min(gfp->samplerate_out / 2, gfp->lowpassfreq); + + if (cfg->vbr == vbr_off) { + gfp->compression_ratio = gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->brate); + } + if (cfg->vbr == vbr_abr) { + gfp->compression_ratio = + gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->VBR_mean_bitrate_kbps); + } + + cfg->disable_reservoir = gfp->disable_reservoir; + cfg->lowpassfreq = gfp->lowpassfreq; + cfg->highpassfreq = gfp->highpassfreq; + cfg->samplerate_in = gfp->samplerate_in; + cfg->samplerate_out = gfp->samplerate_out; + cfg->mode_gr = cfg->samplerate_out <= 24000 ? 1 : 2; /* Number of granules per frame */ + + + /* + * sample freq bitrate compression ratio + * [kHz] [kbps/channel] for 16 bit input + * 44.1 56 12.6 + * 44.1 64 11.025 + * 44.1 80 8.82 + * 22.05 24 14.7 + * 22.05 32 11.025 + * 22.05 40 8.82 + * 16 16 16.0 + * 16 24 10.667 + * + */ + /* + * For VBR, take a guess at the compression_ratio. + * For example: + * + * VBR_q compression like + * - 4.4 320 kbps/44 kHz + * 0...1 5.5 256 kbps/44 kHz + * 2 7.3 192 kbps/44 kHz + * 4 8.8 160 kbps/44 kHz + * 6 11 128 kbps/44 kHz + * 9 14.7 96 kbps + * + * for lower bitrates, downsample with --resample + */ + + switch (cfg->vbr) { + case vbr_mt: + case vbr_rh: + case vbr_mtrh: + { + /*numbers are a bit strange, but they determine the lowpass value */ + FLOAT const cmp[] = { 5.7, 6.5, 7.3, 8.2, 10, 11.9, 13, 14, 15, 16.5 }; + gfp->compression_ratio = cmp[gfp->VBR_q]; + } + break; + case vbr_abr: + gfp->compression_ratio = + cfg->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->VBR_mean_bitrate_kbps); + break; + default: + gfp->compression_ratio = cfg->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->brate); + break; + } + + + /* mode = -1 (not set by user) or + * mode = MONO (because of only 1 input channel). + * If mode has not been set, then select J-STEREO + */ + if (gfp->mode == NOT_SET) { + gfp->mode = JOINT_STEREO; + } + + cfg->mode = gfp->mode; + + + /* apply user driven high pass filter */ + if (cfg->highpassfreq > 0) { + cfg->highpass1 = 2. * cfg->highpassfreq; + + if (gfp->highpasswidth >= 0) + cfg->highpass2 = 2. * (cfg->highpassfreq + gfp->highpasswidth); + else /* 0% above on default */ + cfg->highpass2 = (1 + 0.00) * 2. * cfg->highpassfreq; + + cfg->highpass1 /= cfg->samplerate_out; + cfg->highpass2 /= cfg->samplerate_out; + } + else { + cfg->highpass1 = 0; + cfg->highpass2 = 0; + } + /* apply user driven low pass filter */ + cfg->lowpass1 = 0; + cfg->lowpass2 = 0; + if (cfg->lowpassfreq > 0 && cfg->lowpassfreq < (cfg->samplerate_out / 2) ) { + cfg->lowpass2 = 2. * cfg->lowpassfreq; + if (gfp->lowpasswidth >= 0) { + cfg->lowpass1 = 2. * (cfg->lowpassfreq - gfp->lowpasswidth); + if (cfg->lowpass1 < 0) /* has to be >= 0 */ + cfg->lowpass1 = 0; + } + else { /* 0% below on default */ + cfg->lowpass1 = (1 - 0.00) * 2. * cfg->lowpassfreq; + } + cfg->lowpass1 /= cfg->samplerate_out; + cfg->lowpass2 /= cfg->samplerate_out; + } + + + + + /**********************************************************************/ + /* compute info needed for polyphase filter (filter type==0, default) */ + /**********************************************************************/ + lame_init_params_ppflt(gfc); + + + /******************************************************* + * samplerate and bitrate index + *******************************************************/ + cfg->samplerate_index = SmpFrqIndex(cfg->samplerate_out, &cfg->version); + assert(cfg->samplerate_index >= 0); + + if (cfg->vbr == vbr_off) { + if (cfg->free_format) { + gfc->ov_enc.bitrate_index = 0; + } + else { + gfp->brate = FindNearestBitrate(gfp->brate, cfg->version, cfg->samplerate_out); + gfc->ov_enc.bitrate_index = BitrateIndex(gfp->brate, cfg->version, cfg->samplerate_out); + if (gfc->ov_enc.bitrate_index <= 0) { + /* This never happens, because of preceding FindNearestBitrate! + * But, set a sane value, just in case + */ + assert(0); + gfc->ov_enc.bitrate_index = 8; + } + } + } + else { + gfc->ov_enc.bitrate_index = 1; + } + + init_bit_stream_w(gfc); + + j = cfg->samplerate_index + (3 * cfg->version) + 6 * (cfg->samplerate_out < 16000); + for (i = 0; i < SBMAX_l + 1; i++) + gfc->scalefac_band.l[i] = sfBandIndex[j].l[i]; + + for (i = 0; i < PSFB21 + 1; i++) { + int const size = (gfc->scalefac_band.l[22] - gfc->scalefac_band.l[21]) / PSFB21; + int const start = gfc->scalefac_band.l[21] + i * size; + gfc->scalefac_band.psfb21[i] = start; + } + gfc->scalefac_band.psfb21[PSFB21] = 576; + + for (i = 0; i < SBMAX_s + 1; i++) + gfc->scalefac_band.s[i] = sfBandIndex[j].s[i]; + + for (i = 0; i < PSFB12 + 1; i++) { + int const size = (gfc->scalefac_band.s[13] - gfc->scalefac_band.s[12]) / PSFB12; + int const start = gfc->scalefac_band.s[12] + i * size; + gfc->scalefac_band.psfb12[i] = start; + } + gfc->scalefac_band.psfb12[PSFB12] = 192; + + /* determine the mean bitrate for main data */ + if (cfg->mode_gr == 2) /* MPEG 1 */ + cfg->sideinfo_len = (cfg->channels_out == 1) ? 4 + 17 : 4 + 32; + else /* MPEG 2 */ + cfg->sideinfo_len = (cfg->channels_out == 1) ? 4 + 9 : 4 + 17; + + if (cfg->error_protection) + cfg->sideinfo_len += 2; + + { + int k; + + for (k = 0; k < 19; k++) + gfc->sv_enc.pefirbuf[k] = 700 * cfg->mode_gr * cfg->channels_out; + + if (gfp->ATHtype == -1) + gfp->ATHtype = 4; + } + + assert(gfp->VBR_q <= 9); + assert(gfp->VBR_q >= 0); + + switch (cfg->vbr) { + + case vbr_mt: + case vbr_mtrh:{ + if (gfp->strict_ISO < 0) { + gfp->strict_ISO = MDB_MAXIMUM; + } + if (gfp->useTemporal < 0) { + gfp->useTemporal = 0; /* off by default for this VBR mode */ + } + + (void) apply_preset(gfp, 500 - (gfp->VBR_q * 10), 0); + /* The newer VBR code supports only a limited + subset of quality levels: + 9-5=5 are the same, uses x^3/4 quantization + 4-0=0 are the same 5 plus best huffman divide code + */ + if (gfp->quality < 0) + gfp->quality = LAME_DEFAULT_QUALITY; + if (gfp->quality < 5) + gfp->quality = 0; + if (gfp->quality > 7) + gfp->quality = 7; + + /* sfb21 extra only with MPEG-1 at higher sampling rates + */ + if (gfp->experimentalY) + gfc->sv_qnt.sfb21_extra = 0; + else + gfc->sv_qnt.sfb21_extra = (cfg->samplerate_out > 44000); + + break; + + } + case vbr_rh:{ + + (void) apply_preset(gfp, 500 - (gfp->VBR_q * 10), 0); + + /* sfb21 extra only with MPEG-1 at higher sampling rates + */ + if (gfp->experimentalY) + gfc->sv_qnt.sfb21_extra = 0; + else + gfc->sv_qnt.sfb21_extra = (cfg->samplerate_out > 44000); + + /* VBR needs at least the output of GPSYCHO, + * so we have to garantee that by setting a minimum + * quality level, actually level 6 does it. + * down to level 6 + */ + if (gfp->quality > 6) + gfp->quality = 6; + + + if (gfp->quality < 0) + gfp->quality = LAME_DEFAULT_QUALITY; + + break; + } + + default: /* cbr/abr */ { + + /* no sfb21 extra with CBR code + */ + gfc->sv_qnt.sfb21_extra = 0; + + if (gfp->quality < 0) + gfp->quality = LAME_DEFAULT_QUALITY; + + + if (cfg->vbr == vbr_off) + (void) lame_set_VBR_mean_bitrate_kbps(gfp, gfp->brate); + /* second, set parameters depending on bitrate */ + (void) apply_preset(gfp, gfp->VBR_mean_bitrate_kbps, 0); + gfp->VBR = cfg->vbr; + + break; + } + } + + /*initialize default values common for all modes */ + + gfc->sv_qnt.mask_adjust = gfp->maskingadjust; + gfc->sv_qnt.mask_adjust_short = gfp->maskingadjust_short; + + /* just another daily changing developer switch */ + if (gfp->tune) { + gfc->sv_qnt.mask_adjust += gfp->tune_value_a; + gfc->sv_qnt.mask_adjust_short += gfp->tune_value_a; + } + + + if (cfg->vbr != vbr_off) { /* choose a min/max bitrate for VBR */ + /* if the user didn't specify VBR_max_bitrate: */ + cfg->vbr_min_bitrate_index = 1; /* default: allow 8 kbps (MPEG-2) or 32 kbps (MPEG-1) */ + cfg->vbr_max_bitrate_index = 14; /* default: allow 160 kbps (MPEG-2) or 320 kbps (MPEG-1) */ + if (cfg->samplerate_out < 16000) + cfg->vbr_max_bitrate_index = 8; /* default: allow 64 kbps (MPEG-2.5) */ + if (gfp->VBR_min_bitrate_kbps) { + gfp->VBR_min_bitrate_kbps = + FindNearestBitrate(gfp->VBR_min_bitrate_kbps, cfg->version, cfg->samplerate_out); + cfg->vbr_min_bitrate_index = + BitrateIndex(gfp->VBR_min_bitrate_kbps, cfg->version, cfg->samplerate_out); + if (cfg->vbr_min_bitrate_index < 0) { + /* This never happens, because of preceding FindNearestBitrate! + * But, set a sane value, just in case + */ + assert(0); + cfg->vbr_min_bitrate_index = 1; + } + } + if (gfp->VBR_max_bitrate_kbps) { + gfp->VBR_max_bitrate_kbps = + FindNearestBitrate(gfp->VBR_max_bitrate_kbps, cfg->version, cfg->samplerate_out); + cfg->vbr_max_bitrate_index = + BitrateIndex(gfp->VBR_max_bitrate_kbps, cfg->version, cfg->samplerate_out); + if (cfg->vbr_max_bitrate_index < 0) { + /* This never happens, because of preceding FindNearestBitrate! + * But, set a sane value, just in case + */ + assert(0); + cfg->vbr_max_bitrate_index = cfg->samplerate_out < 16000 ? 8 : 14; + } + } + gfp->VBR_min_bitrate_kbps = bitrate_table[cfg->version][cfg->vbr_min_bitrate_index]; + gfp->VBR_max_bitrate_kbps = bitrate_table[cfg->version][cfg->vbr_max_bitrate_index]; + gfp->VBR_mean_bitrate_kbps = + Min(bitrate_table[cfg->version][cfg->vbr_max_bitrate_index], + gfp->VBR_mean_bitrate_kbps); + gfp->VBR_mean_bitrate_kbps = + Max(bitrate_table[cfg->version][cfg->vbr_min_bitrate_index], + gfp->VBR_mean_bitrate_kbps); + } + + cfg->preset = gfp->preset; + cfg->write_lame_tag = gfp->write_lame_tag; + gfc->sv_qnt.substep_shaping = gfp->substep_shaping; + cfg->noise_shaping = gfp->noise_shaping; + cfg->subblock_gain = gfp->subblock_gain; + cfg->use_best_huffman = gfp->use_best_huffman; + cfg->avg_bitrate = gfp->brate; + cfg->vbr_avg_bitrate_kbps = gfp->VBR_mean_bitrate_kbps; + cfg->compression_ratio = gfp->compression_ratio; + + /* initialize internal qval settings */ + lame_init_qval(gfp); + + + /* automatic ATH adjustment on + */ + if (gfp->athaa_type < 0) + gfc->ATH->use_adjust = 3; + else + gfc->ATH->use_adjust = gfp->athaa_type; + + + /* initialize internal adaptive ATH settings -jd */ + gfc->ATH->aa_sensitivity_p = pow(10.0, gfp->athaa_sensitivity / -10.0); + + + if (gfp->short_blocks == short_block_not_set) { + gfp->short_blocks = short_block_allowed; + } + + /*Note Jan/2003: Many hardware decoders cannot handle short blocks in regular + stereo mode unless they are coupled (same type in both channels) + it is a rare event (1 frame per min. or so) that LAME would use + uncoupled short blocks, so lets turn them off until we decide + how to handle this. No other encoders allow uncoupled short blocks, + even though it is in the standard. */ + /* rh 20040217: coupling makes no sense for mono and dual-mono streams + */ + if (gfp->short_blocks == short_block_allowed + && (cfg->mode == JOINT_STEREO || cfg->mode == STEREO)) { + gfp->short_blocks = short_block_coupled; + } + + cfg->short_blocks = gfp->short_blocks; + + + if (lame_get_quant_comp(gfp) < 0) + (void) lame_set_quant_comp(gfp, 1); + if (lame_get_quant_comp_short(gfp) < 0) + (void) lame_set_quant_comp_short(gfp, 0); + + if (lame_get_msfix(gfp) < 0) + lame_set_msfix(gfp, 0); + + /* select psychoacoustic model */ + (void) lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 1); + + if (gfp->ATHtype < 0) + gfp->ATHtype = 4; + + if (gfp->ATHcurve < 0) + gfp->ATHcurve = 4; + + if (gfp->interChRatio < 0) + gfp->interChRatio = 0; + + if (gfp->useTemporal < 0) + gfp->useTemporal = 1; /* on by default */ + + + cfg->interChRatio = gfp->interChRatio; + cfg->msfix = gfp->msfix; + cfg->ATH_offset_db = 0-gfp->ATH_lower_db; + cfg->ATH_offset_factor = powf(10.f, cfg->ATH_offset_db * 0.1f); + cfg->ATHcurve = gfp->ATHcurve; + cfg->ATHtype = gfp->ATHtype; + cfg->ATHonly = gfp->ATHonly; + cfg->ATHshort = gfp->ATHshort; + cfg->noATH = gfp->noATH; + + cfg->quant_comp = gfp->quant_comp; + cfg->quant_comp_short = gfp->quant_comp_short; + + cfg->use_temporal_masking_effect = gfp->useTemporal; + if (cfg->mode == JOINT_STEREO) { + cfg->use_safe_joint_stereo = gfp->exp_nspsytune & 2; + } + else { + cfg->use_safe_joint_stereo = 0; + } + { + cfg->adjust_bass_db = (gfp->exp_nspsytune >> 2) & 63; + if (cfg->adjust_bass_db >= 32.f) + cfg->adjust_bass_db -= 64.f; + cfg->adjust_bass_db *= 0.25f; + + cfg->adjust_alto_db = (gfp->exp_nspsytune >> 8) & 63; + if (cfg->adjust_alto_db >= 32.f) + cfg->adjust_alto_db -= 64.f; + cfg->adjust_alto_db *= 0.25f; + + cfg->adjust_treble_db = (gfp->exp_nspsytune >> 14) & 63; + if (cfg->adjust_treble_db >= 32.f) + cfg->adjust_treble_db -= 64.f; + cfg->adjust_treble_db *= 0.25f; + + /* to be compatible with Naoki's original code, the next 6 bits + * define only the amount of changing treble for sfb21 */ + cfg->adjust_sfb21_db = (gfp->exp_nspsytune >> 20) & 63; + if (cfg->adjust_sfb21_db >= 32.f) + cfg->adjust_sfb21_db -= 64.f; + cfg->adjust_sfb21_db *= 0.25f; + cfg->adjust_sfb21_db += cfg->adjust_treble_db; + } + + /* Setting up the PCM input data transform matrix, to apply + * user defined re-scaling, and or two-to-one channel downmix. + */ + { + FLOAT m[2][2] = { {1.0f, 0.0f}, {0.0f, 1.0f} }; + + /* user selected scaling of the samples */ + m[0][0] *= gfp->scale; + m[0][1] *= gfp->scale; + m[1][0] *= gfp->scale; + m[1][1] *= gfp->scale; + /* user selected scaling of the channel 0 (left) samples */ + m[0][0] *= gfp->scale_left; + m[0][1] *= gfp->scale_left; + /* user selected scaling of the channel 1 (right) samples */ + m[1][0] *= gfp->scale_right; + m[1][1] *= gfp->scale_right; + /* Downsample to Mono if 2 channels in and 1 channel out */ + if (cfg->channels_in == 2 && cfg->channels_out == 1) { + m[0][0] = 0.5f * (m[0][0] + m[1][0]); + m[0][1] = 0.5f * (m[0][1] + m[1][1]); + m[1][0] = 0; + m[1][1] = 0; + } + cfg->pcm_transform[0][0] = m[0][0]; + cfg->pcm_transform[0][1] = m[0][1]; + cfg->pcm_transform[1][0] = m[1][0]; + cfg->pcm_transform[1][1] = m[1][1]; + } + + /* padding method as described in + * "MPEG-Layer3 / Bitstream Syntax and Decoding" + * by Martin Sieler, Ralph Sperschneider + * + * note: there is no padding for the very first frame + * + * Robert Hegemann 2000-06-22 + */ + gfc->sv_enc.slot_lag = gfc->sv_enc.frac_SpF = 0; + if (cfg->vbr == vbr_off) + gfc->sv_enc.slot_lag = gfc->sv_enc.frac_SpF + = ((cfg->version + 1) * 72000L * cfg->avg_bitrate) % cfg->samplerate_out; + + (void) lame_init_bitstream(gfp); + + iteration_init(gfc); + (void) psymodel_init(gfp); + + cfg->buffer_constraint = get_max_frame_buffer_size_by_constraint(cfg, gfp->strict_ISO); + + + cfg->findReplayGain = gfp->findReplayGain; + cfg->decode_on_the_fly = gfp->decode_on_the_fly; + + if (cfg->decode_on_the_fly) + cfg->findPeakSample = 1; + + if (cfg->findReplayGain) { + if (InitGainAnalysis(gfc->sv_rpg.rgdata, cfg->samplerate_out) == INIT_GAIN_ANALYSIS_ERROR) { + /* Actually this never happens, our samplerates are the ones RG accepts! + * But just in case, turn RG off + */ + assert(0); + cfg->findReplayGain = 0; + } + } + +#ifdef DECODE_ON_THE_FLY + if (cfg->decode_on_the_fly && !gfp->decode_only) { + if (gfc->hip) { + hip_decode_exit(gfc->hip); + } + gfc->hip = hip_decode_init(); + /* report functions */ + hip_set_errorf(gfc->hip, gfp->report.errorf); + hip_set_debugf(gfc->hip, gfp->report.debugf); + hip_set_msgf(gfc->hip, gfp->report.msgf); + } +#endif + /* updating lame internal flags finished successful */ + gfc->lame_init_params_successful = 1; + return 0; +} + +static void +concatSep(char* dest, char const* sep, char const* str) +{ + if (*dest != 0) strcat(dest, sep); + strcat(dest, str); +} + +/* + * print_config + * + * Prints some selected information about the coding parameters via + * the macro command MSGF(), which is currently mapped to lame_errorf + * (reports via a error function?), which is a printf-like function + * for . + */ + +void +lame_print_config(const lame_global_flags * gfp) +{ + lame_internal_flags const *const gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + double const out_samplerate = cfg->samplerate_out; + double const in_samplerate = cfg->samplerate_in; + + MSGF(gfc, "LAME %s %s (%s)\n", get_lame_version(), get_lame_os_bitness(), get_lame_url()); + +#if (LAME_ALPHA_VERSION) + MSGF(gfc, "warning: alpha versions should be used for testing only\n"); +#endif + if (gfc->CPU_features.MMX + || gfc->CPU_features.AMD_3DNow || gfc->CPU_features.SSE || gfc->CPU_features.SSE2) { + char text[256] = { 0 }; + int fft_asm_used = 0; +#ifdef HAVE_NASM + if (gfc->CPU_features.AMD_3DNow) { + fft_asm_used = 1; + } + else if (gfc->CPU_features.SSE) { + fft_asm_used = 2; + } +#else +# if defined( HAVE_XMMINTRIN_H ) && defined( MIN_ARCH_SSE ) + { + fft_asm_used = 3; + } +# endif +#endif + if (gfc->CPU_features.MMX) { +#ifdef MMX_choose_table + concatSep(text, ", ", "MMX (ASM used)"); +#else + concatSep(text, ", ", "MMX"); +#endif + } + if (gfc->CPU_features.AMD_3DNow) { + concatSep(text, ", ", (fft_asm_used == 1) ? "3DNow! (ASM used)" : "3DNow!"); + } + if (gfc->CPU_features.SSE) { +#if defined(HAVE_XMMINTRIN_H) + concatSep(text, ", ", "SSE (ASM used)"); +#else + concatSep(text, ", ", (fft_asm_used == 2) ? "SSE (ASM used)" : "SSE"); +#endif + } + if (gfc->CPU_features.SSE2) { + concatSep(text, ", ", (fft_asm_used == 3) ? "SSE2 (ASM used)" : "SSE2"); + } + MSGF(gfc, "CPU features: %s\n", text); + } + + if (cfg->channels_in == 2 && cfg->channels_out == 1 /* mono */ ) { + MSGF(gfc, "Autoconverting from stereo to mono. Setting encoding to mono mode.\n"); + } + + if (isResamplingNecessary(cfg)) { + MSGF(gfc, "Resampling: input %g kHz output %g kHz\n", + 1.e-3 * in_samplerate, 1.e-3 * out_samplerate); + } + + if (cfg->highpass2 > 0.) + MSGF(gfc, + "Using polyphase highpass filter, transition band: %5.0f Hz - %5.0f Hz\n", + 0.5 * cfg->highpass1 * out_samplerate, 0.5 * cfg->highpass2 * out_samplerate); + if (0. < cfg->lowpass1 || 0. < cfg->lowpass2) { + MSGF(gfc, + "Using polyphase lowpass filter, transition band: %5.0f Hz - %5.0f Hz\n", + 0.5 * cfg->lowpass1 * out_samplerate, 0.5 * cfg->lowpass2 * out_samplerate); + } + else { + MSGF(gfc, "polyphase lowpass filter disabled\n"); + } + + if (cfg->free_format) { + MSGF(gfc, "Warning: many decoders cannot handle free format bitstreams\n"); + if (cfg->avg_bitrate > 320) { + MSGF(gfc, + "Warning: many decoders cannot handle free format bitrates >320 kbps (see documentation)\n"); + } + } +} + + +/** rh: + * some pretty printing is very welcome at this point! + * so, if someone is willing to do so, please do it! + * add more, if you see more... + */ +void +lame_print_internals(const lame_global_flags * gfp) +{ + lame_internal_flags const *const gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + const char *pc = ""; + + /* compiler/processor optimizations, operational, etc. + */ + MSGF(gfc, "\nmisc:\n\n"); + + MSGF(gfc, "\tscaling: %g\n", gfp->scale); + MSGF(gfc, "\tch0 (left) scaling: %g\n", gfp->scale_left); + MSGF(gfc, "\tch1 (right) scaling: %g\n", gfp->scale_right); + switch (cfg->use_best_huffman) { + default: + pc = "normal"; + break; + case 1: + pc = "best (outside loop)"; + break; + case 2: + pc = "best (inside loop, slow)"; + break; + } + MSGF(gfc, "\thuffman search: %s\n", pc); + MSGF(gfc, "\texperimental Y=%d\n", gfp->experimentalY); + MSGF(gfc, "\t...\n"); + + /* everything controlling the stream format + */ + MSGF(gfc, "\nstream format:\n\n"); + switch (cfg->version) { + case 0: + pc = "2.5"; + break; + case 1: + pc = "1"; + break; + case 2: + pc = "2"; + break; + default: + pc = "?"; + break; + } + MSGF(gfc, "\tMPEG-%s Layer 3\n", pc); + switch (cfg->mode) { + case JOINT_STEREO: + pc = "joint stereo"; + break; + case STEREO: + pc = "stereo"; + break; + case DUAL_CHANNEL: + pc = "dual channel"; + break; + case MONO: + pc = "mono"; + break; + case NOT_SET: + pc = "not set (error)"; + break; + default: + pc = "unknown (error)"; + break; + } + MSGF(gfc, "\t%d channel - %s\n", cfg->channels_out, pc); + + switch (cfg->vbr) { + case vbr_off: + pc = "off"; + break; + default: + pc = "all"; + break; + } + MSGF(gfc, "\tpadding: %s\n", pc); + + if (vbr_default == cfg->vbr) + pc = "(default)"; + else if (cfg->free_format) + pc = "(free format)"; + else + pc = ""; + switch (cfg->vbr) { + case vbr_off: + MSGF(gfc, "\tconstant bitrate - CBR %s\n", pc); + break; + case vbr_abr: + MSGF(gfc, "\tvariable bitrate - ABR %s\n", pc); + break; + case vbr_rh: + MSGF(gfc, "\tvariable bitrate - VBR rh %s\n", pc); + break; + case vbr_mt: + MSGF(gfc, "\tvariable bitrate - VBR mt %s\n", pc); + break; + case vbr_mtrh: + MSGF(gfc, "\tvariable bitrate - VBR mtrh %s\n", pc); + break; + default: + MSGF(gfc, "\t ?? oops, some new one ?? \n"); + break; + } + if (cfg->write_lame_tag) + MSGF(gfc, "\tusing LAME Tag\n"); + MSGF(gfc, "\t...\n"); + + /* everything controlling psychoacoustic settings, like ATH, etc. + */ + MSGF(gfc, "\npsychoacoustic:\n\n"); + + switch (cfg->short_blocks) { + default: + case short_block_not_set: + pc = "?"; + break; + case short_block_allowed: + pc = "allowed"; + break; + case short_block_coupled: + pc = "channel coupled"; + break; + case short_block_dispensed: + pc = "dispensed"; + break; + case short_block_forced: + pc = "forced"; + break; + } + MSGF(gfc, "\tusing short blocks: %s\n", pc); + MSGF(gfc, "\tsubblock gain: %d\n", cfg->subblock_gain); + MSGF(gfc, "\tadjust masking: %g dB\n", gfc->sv_qnt.mask_adjust); + MSGF(gfc, "\tadjust masking short: %g dB\n", gfc->sv_qnt.mask_adjust_short); + MSGF(gfc, "\tquantization comparison: %d\n", cfg->quant_comp); + MSGF(gfc, "\t ^ comparison short blocks: %d\n", cfg->quant_comp_short); + MSGF(gfc, "\tnoise shaping: %d\n", cfg->noise_shaping); + MSGF(gfc, "\t ^ amplification: %d\n", cfg->noise_shaping_amp); + MSGF(gfc, "\t ^ stopping: %d\n", cfg->noise_shaping_stop); + + pc = "using"; + if (cfg->ATHshort) + pc = "the only masking for short blocks"; + if (cfg->ATHonly) + pc = "the only masking"; + if (cfg->noATH) + pc = "not used"; + MSGF(gfc, "\tATH: %s\n", pc); + MSGF(gfc, "\t ^ type: %d\n", cfg->ATHtype); + MSGF(gfc, "\t ^ shape: %g%s\n", cfg->ATHcurve, " (only for type 4)"); + MSGF(gfc, "\t ^ level adjustement: %g dB\n", cfg->ATH_offset_db); + MSGF(gfc, "\t ^ adjust type: %d\n", gfc->ATH->use_adjust); + MSGF(gfc, "\t ^ adjust sensitivity power: %f\n", gfc->ATH->aa_sensitivity_p); + + MSGF(gfc, "\texperimental psy tunings by Naoki Shibata\n"); + MSGF(gfc, "\t adjust masking bass=%g dB, alto=%g dB, treble=%g dB, sfb21=%g dB\n", + 10 * log10(gfc->sv_qnt.longfact[0]), + 10 * log10(gfc->sv_qnt.longfact[7]), + 10 * log10(gfc->sv_qnt.longfact[14]), 10 * log10(gfc->sv_qnt.longfact[21])); + + pc = cfg->use_temporal_masking_effect ? "yes" : "no"; + MSGF(gfc, "\tusing temporal masking effect: %s\n", pc); + MSGF(gfc, "\tinterchannel masking ratio: %g\n", cfg->interChRatio); + MSGF(gfc, "\t...\n"); + + /* that's all ? + */ + MSGF(gfc, "\n"); + return; +} + + +static void +save_gain_values(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + RpgStateVar_t const *const rsv = &gfc->sv_rpg; + RpgResult_t *const rov = &gfc->ov_rpg; + /* save the ReplayGain value */ + if (cfg->findReplayGain) { + FLOAT const RadioGain = (FLOAT) GetTitleGain(rsv->rgdata); + if (NEQ(RadioGain, GAIN_NOT_ENOUGH_SAMPLES)) { + rov->RadioGain = (int) floor(RadioGain * 10.0 + 0.5); /* round to nearest */ + } + else { + rov->RadioGain = 0; + } + } + + /* find the gain and scale change required for no clipping */ + if (cfg->findPeakSample) { + rov->noclipGainChange = (int) ceil(log10(rov->PeakSample / 32767.0) * 20.0 * 10.0); /* round up */ + + if (rov->noclipGainChange > 0) { /* clipping occurs */ + rov->noclipScale = floor((32767.0f / rov->PeakSample) * 100.0f) / 100.0f; /* round down */ + } + else /* no clipping */ + rov->noclipScale = -1.0f; + } +} + + + +static int +update_inbuffer_size(lame_internal_flags * gfc, const int nsamples) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + if (esv->in_buffer_0 == 0 || esv->in_buffer_nsamples < nsamples) { + if (esv->in_buffer_0) { + free(esv->in_buffer_0); + } + if (esv->in_buffer_1) { + free(esv->in_buffer_1); + } + esv->in_buffer_0 = lame_calloc(sample_t, nsamples); + esv->in_buffer_1 = lame_calloc(sample_t, nsamples); + esv->in_buffer_nsamples = nsamples; + } + if (esv->in_buffer_0 == NULL || esv->in_buffer_1 == NULL) { + if (esv->in_buffer_0) { + free(esv->in_buffer_0); + } + if (esv->in_buffer_1) { + free(esv->in_buffer_1); + } + esv->in_buffer_0 = 0; + esv->in_buffer_1 = 0; + esv->in_buffer_nsamples = 0; + ERRORF(gfc, "Error: can't allocate in_buffer buffer\n"); + return -2; + } + return 0; +} + + +static int +calcNeeded(SessionConfig_t const * cfg) +{ + int mf_needed; + int pcm_samples_per_frame = 576 * cfg->mode_gr; + + /* some sanity checks */ +#if ENCDELAY < MDCTDELAY +# error ENCDELAY is less than MDCTDELAY, see encoder.h +#endif +#if FFTOFFSET > BLKSIZE +# error FFTOFFSET is greater than BLKSIZE, see encoder.h +#endif + + mf_needed = BLKSIZE + pcm_samples_per_frame - FFTOFFSET; /* amount needed for FFT */ + /*mf_needed = Max(mf_needed, 286 + 576 * (1 + gfc->mode_gr)); */ + mf_needed = Max(mf_needed, 512 + pcm_samples_per_frame - 32); + + assert(MFSIZE >= mf_needed); + + return mf_needed; +} + + +/* + * THE MAIN LAME ENCODING INTERFACE + * mt 3/00 + * + * input pcm data, output (maybe) mp3 frames. + * This routine handles all buffering, resampling and filtering for you. + * The required mp3buffer_size can be computed from num_samples, + * samplerate and encoding rate, but here is a worst case estimate: + * + * mp3buffer_size in bytes = 1.25*num_samples + 7200 + * + * return code = number of bytes output in mp3buffer. can be 0 + * + * NOTE: this routine uses LAME's internal PCM data representation, + * 'sample_t'. It should not be used by any application. + * applications should use lame_encode_buffer(), + * lame_encode_buffer_float() + * lame_encode_buffer_int() + * etc... depending on what type of data they are working with. +*/ +static int +lame_encode_buffer_sample_t(lame_internal_flags * gfc, + int nsamples, unsigned char *mp3buf, const int mp3buf_size) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int pcm_samples_per_frame = 576 * cfg->mode_gr; + int mp3size = 0, ret, i, ch, mf_needed; + int mp3out; + sample_t *mfbuf[2]; + sample_t *in_buffer[2]; + + if (gfc->class_id != LAME_ID) + return -3; + + if (nsamples == 0) + return 0; + + /* copy out any tags that may have been written into bitstream */ + { /* if user specifed buffer size = 0, dont check size */ + int const buf_size = mp3buf_size == 0 ? INT_MAX : mp3buf_size; + mp3out = copy_buffer(gfc, mp3buf, buf_size, 0); + } + if (mp3out < 0) + return mp3out; /* not enough buffer space */ + mp3buf += mp3out; + mp3size += mp3out; + + in_buffer[0] = esv->in_buffer_0; + in_buffer[1] = esv->in_buffer_1; + + mf_needed = calcNeeded(cfg); + + mfbuf[0] = esv->mfbuf[0]; + mfbuf[1] = esv->mfbuf[1]; + + while (nsamples > 0) { + sample_t const *in_buffer_ptr[2]; + int n_in = 0; /* number of input samples processed with fill_buffer */ + int n_out = 0; /* number of samples output with fill_buffer */ + /* n_in <> n_out if we are resampling */ + + in_buffer_ptr[0] = in_buffer[0]; + in_buffer_ptr[1] = in_buffer[1]; + /* copy in new samples into mfbuf, with resampling */ + fill_buffer(gfc, mfbuf, &in_buffer_ptr[0], nsamples, &n_in, &n_out); + + /* compute ReplayGain of resampled input if requested */ + if (cfg->findReplayGain && !cfg->decode_on_the_fly) + if (AnalyzeSamples + (gfc->sv_rpg.rgdata, &mfbuf[0][esv->mf_size], &mfbuf[1][esv->mf_size], n_out, + cfg->channels_out) == GAIN_ANALYSIS_ERROR) + return -6; + + + + /* update in_buffer counters */ + nsamples -= n_in; + in_buffer[0] += n_in; + if (cfg->channels_out == 2) + in_buffer[1] += n_in; + + /* update mfbuf[] counters */ + esv->mf_size += n_out; + assert(esv->mf_size <= MFSIZE); + + /* lame_encode_flush may have set gfc->mf_sample_to_encode to 0 + * so we have to reinitialize it here when that happened. + */ + if (esv->mf_samples_to_encode < 1) { + esv->mf_samples_to_encode = ENCDELAY + POSTDELAY; + } + esv->mf_samples_to_encode += n_out; + + + if (esv->mf_size >= mf_needed) { + /* encode the frame. */ + /* mp3buf = pointer to current location in buffer */ + /* mp3buf_size = size of original mp3 output buffer */ + /* = 0 if we should not worry about the */ + /* buffer size because calling program is */ + /* to lazy to compute it */ + /* mp3size = size of data written to buffer so far */ + /* mp3buf_size-mp3size = amount of space avalable */ + + int buf_size = mp3buf_size - mp3size; + if (mp3buf_size == 0) + buf_size = INT_MAX; + + ret = lame_encode_mp3_frame(gfc, mfbuf[0], mfbuf[1], mp3buf, buf_size); + + if (ret < 0) + return ret; + mp3buf += ret; + mp3size += ret; + + /* shift out old samples */ + esv->mf_size -= pcm_samples_per_frame; + esv->mf_samples_to_encode -= pcm_samples_per_frame; + for (ch = 0; ch < cfg->channels_out; ch++) + for (i = 0; i < esv->mf_size; i++) + mfbuf[ch][i] = mfbuf[ch][i + pcm_samples_per_frame]; + } + } + assert(nsamples == 0); + + return mp3size; +} + +enum PCMSampleType +{ pcm_short_type +, pcm_int_type +, pcm_long_type +, pcm_float_type +, pcm_double_type +}; + +static void +lame_copy_inbuffer(lame_internal_flags* gfc, + void const* l, void const* r, int nsamples, + enum PCMSampleType pcm_type, int jump, FLOAT s) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + sample_t* ib0 = esv->in_buffer_0; + sample_t* ib1 = esv->in_buffer_1; + FLOAT m[2][2]; + + /* Apply user defined re-scaling */ + m[0][0] = s * cfg->pcm_transform[0][0]; + m[0][1] = s * cfg->pcm_transform[0][1]; + m[1][0] = s * cfg->pcm_transform[1][0]; + m[1][1] = s * cfg->pcm_transform[1][1]; + + /* make a copy of input buffer, changing type to sample_t */ +#define COPY_AND_TRANSFORM(T) \ +{ \ + T const *bl = l, *br = r; \ + int i; \ + for (i = 0; i < nsamples; i++) { \ + sample_t const xl = *bl; \ + sample_t const xr = *br; \ + sample_t const u = xl * m[0][0] + xr * m[0][1]; \ + sample_t const v = xl * m[1][0] + xr * m[1][1]; \ + ib0[i] = u; \ + ib1[i] = v; \ + bl += jump; \ + br += jump; \ + } \ +} + switch ( pcm_type ) { + case pcm_short_type: + COPY_AND_TRANSFORM(short int); + break; + case pcm_int_type: + COPY_AND_TRANSFORM(int); + break; + case pcm_long_type: + COPY_AND_TRANSFORM(long int); + break; + case pcm_float_type: + COPY_AND_TRANSFORM(float); + break; + case pcm_double_type: + COPY_AND_TRANSFORM(double); + break; + } +} + + +static int +lame_encode_buffer_template(lame_global_flags * gfp, + void const* buffer_l, void const* buffer_r, const int nsamples, + unsigned char *mp3buf, const int mp3buf_size, enum PCMSampleType pcm_type, int aa, FLOAT norm) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + + if (nsamples == 0) + return 0; + + if (update_inbuffer_size(gfc, nsamples) != 0) { + return -2; + } + /* make a copy of input buffer, changing type to sample_t */ + if (cfg->channels_in > 1) { + if (buffer_l == 0 || buffer_r == 0) { + return 0; + } + lame_copy_inbuffer(gfc, buffer_l, buffer_r, nsamples, pcm_type, aa, norm); + } + else { + if (buffer_l == 0) { + return 0; + } + lame_copy_inbuffer(gfc, buffer_l, buffer_l, nsamples, pcm_type, aa, norm); + } + + return lame_encode_buffer_sample_t(gfc, nsamples, mp3buf, mp3buf_size); + } + } + return -3; +} + +int +lame_encode_buffer(lame_global_flags * gfp, + const short int pcm_l[], const short int pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_short_type, 1, 1.0); +} + + +int +lame_encode_buffer_float(lame_global_flags * gfp, + const float pcm_l[], const float pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 32768 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_float_type, 1, 1.0); +} + + +int +lame_encode_buffer_ieee_float(lame_t gfp, + const float pcm_l[], const float pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_float_type, 1, 32767.0); +} + + +int +lame_encode_buffer_interleaved_ieee_float(lame_t gfp, + const float pcm[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm, pcm+1, nsamples, mp3buf, mp3buf_size, pcm_float_type, 2, 32767.0); +} + + +int +lame_encode_buffer_ieee_double(lame_t gfp, + const double pcm_l[], const double pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_double_type, 1, 32767.0); +} + + +int +lame_encode_buffer_interleaved_ieee_double(lame_t gfp, + const double pcm[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm, pcm+1, nsamples, mp3buf, mp3buf_size, pcm_double_type, 2, 32767.0); +} + + +int +lame_encode_buffer_int(lame_global_flags * gfp, + const int pcm_l[], const int pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX_INT for full scale */ + FLOAT const norm = (1.0 / (1L << (8 * sizeof(int) - 16))); + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_int_type, 1, norm); +} + + +int +lame_encode_buffer_long2(lame_global_flags * gfp, + const long pcm_l[], const long pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX_LONG for full scale */ + FLOAT const norm = (1.0 / (1L << (8 * sizeof(long) - 16))); + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_long_type, 1, norm); +} + + +int +lame_encode_buffer_long(lame_global_flags * gfp, + const long pcm_l[], const long pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 32768 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_long_type, 1, 1.0); +} + + + +int +lame_encode_buffer_interleaved(lame_global_flags * gfp, + short int pcm[], int nsamples, + unsigned char *mp3buf, int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX_SHORT for full scale */ + return lame_encode_buffer_template(gfp, pcm, pcm+1, nsamples, mp3buf, mp3buf_size, pcm_short_type, 2, 1.0); +} + + +int +lame_encode_buffer_interleaved_int(lame_t gfp, + const int pcm[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX(int) for full scale */ + FLOAT const norm = (1.0 / (1L << (8 * sizeof(int)-16))); + return lame_encode_buffer_template(gfp, pcm, pcm + 1, nsamples, mp3buf, mp3buf_size, pcm_int_type, 2, norm); +} + + + + +/***************************************************************** + Flush mp3 buffer, pad with ancillary data so last frame is complete. + Reset reservoir size to 0 + but keep all PCM samples and MDCT data in memory + This option is used to break a large file into several mp3 files + that when concatenated together will decode with no gaps + Because we set the reservoir=0, they will also decode seperately + with no errors. +*********************************************************************/ +int +lame_encode_flush_nogap(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size) +{ + int rc = -3; + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + flush_bitstream(gfc); + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size = INT_MAX; + rc = copy_buffer(gfc, mp3buffer, mp3buffer_size, 1); + save_gain_values(gfc); + } + } + return rc; +} + + +/* called by lame_init_params. You can also call this after flush_nogap + if you want to write new id3v2 and Xing VBR tags into the bitstream */ +int +lame_init_bitstream(lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags *const gfc = gfp->internal_flags; + if (gfc != 0) { + gfc->ov_enc.frame_number = 0; + + if (gfp->write_id3tag_automatic) { + (void) id3tag_write_v2(gfp); + } + /* initialize histogram data optionally used by frontend */ + memset(gfc->ov_enc.bitrate_channelmode_hist, 0, + sizeof(gfc->ov_enc.bitrate_channelmode_hist)); + memset(gfc->ov_enc.bitrate_blocktype_hist, 0, + sizeof(gfc->ov_enc.bitrate_blocktype_hist)); + + gfc->ov_rpg.PeakSample = 0.0; + + /* Write initial VBR Header to bitstream and init VBR data */ + if (gfc->cfg.write_lame_tag) + (void) InitVbrTag(gfp); + + + return 0; + } + } + return -3; +} + + +/*****************************************************************/ +/* flush internal PCM sample buffers, then mp3 buffers */ +/* then write id3 v1 tags into bitstream. */ +/*****************************************************************/ + +int +lame_encode_flush(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size) +{ + lame_internal_flags *gfc; + SessionConfig_t const *cfg; + EncStateVar_t *esv; + short int buffer[2][1152]; + int imp3 = 0, mp3count, mp3buffer_size_remaining; + + /* we always add POSTDELAY=288 padding to make sure granule with real + * data can be complety decoded (because of 50% overlap with next granule */ + int end_padding; + int frames_left; + int samples_to_encode; + int pcm_samples_per_frame; + int mf_needed; + int is_resampling_necessary; + double resample_ratio = 1; + + if (!is_lame_global_flags_valid(gfp)) { + return -3; + } + gfc = gfp->internal_flags; + if (!is_lame_internal_flags_valid(gfc)) { + return -3; + } + cfg = &gfc->cfg; + esv = &gfc->sv_enc; + + /* Was flush already called? */ + if (esv->mf_samples_to_encode < 1) { + return 0; + } + pcm_samples_per_frame = 576 * cfg->mode_gr; + mf_needed = calcNeeded(cfg); + + samples_to_encode = esv->mf_samples_to_encode - POSTDELAY; + + memset(buffer, 0, sizeof(buffer)); + mp3count = 0; + + is_resampling_necessary = isResamplingNecessary(cfg); + if (is_resampling_necessary) { + resample_ratio = (double)cfg->samplerate_in / (double)cfg->samplerate_out; + /* delay due to resampling; needs to be fixed, if resampling code gets changed */ + samples_to_encode += 16. / resample_ratio; + } + end_padding = pcm_samples_per_frame - (samples_to_encode % pcm_samples_per_frame); + if (end_padding < 576) + end_padding += pcm_samples_per_frame; + gfc->ov_enc.encoder_padding = end_padding; + + frames_left = (samples_to_encode + end_padding) / pcm_samples_per_frame; + while (frames_left > 0 && imp3 >= 0) { + int const frame_num = gfc->ov_enc.frame_number; + int bunch = mf_needed - esv->mf_size; + + bunch *= resample_ratio; + if (bunch > 1152) bunch = 1152; + if (bunch < 1) bunch = 1; + + mp3buffer_size_remaining = mp3buffer_size - mp3count; + + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = 0; + + /* send in a frame of 0 padding until all internal sample buffers + * are flushed + */ + imp3 = lame_encode_buffer(gfp, buffer[0], buffer[1], bunch, + mp3buffer, mp3buffer_size_remaining); + + mp3buffer += imp3; + mp3count += imp3; + { /* even a single pcm sample can produce several frames! + * for example: 1 Hz input file resampled to 8 kHz mpeg2.5 + */ + int const new_frames = gfc->ov_enc.frame_number - frame_num; + if (new_frames > 0) + frames_left -= new_frames; + } + } + /* Set esv->mf_samples_to_encode to 0, so we may detect + * and break loops calling it more than once in a row. + */ + esv->mf_samples_to_encode = 0; + + if (imp3 < 0) { + /* some type of fatal error */ + return imp3; + } + + mp3buffer_size_remaining = mp3buffer_size - mp3count; + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = INT_MAX; + + /* mp3 related stuff. bit buffer might still contain some mp3 data */ + flush_bitstream(gfc); + imp3 = copy_buffer(gfc, mp3buffer, mp3buffer_size_remaining, 1); + save_gain_values(gfc); + if (imp3 < 0) { + /* some type of fatal error */ + return imp3; + } + mp3buffer += imp3; + mp3count += imp3; + mp3buffer_size_remaining = mp3buffer_size - mp3count; + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = INT_MAX; + + if (gfp->write_id3tag_automatic) { + /* write a id3 tag to the bitstream */ + (void) id3tag_write_v1(gfp); + + imp3 = copy_buffer(gfc, mp3buffer, mp3buffer_size_remaining, 0); + + if (imp3 < 0) { + return imp3; + } + mp3count += imp3; + } +#if 0 + { + int const ed = gfc->ov_enc.encoder_delay; + int const ep = gfc->ov_enc.encoder_padding; + int const ns = (gfc->ov_enc.frame_number * pcm_samples_per_frame) - (ed + ep); + double duration = ns; + duration /= cfg->samplerate_out; + MSGF(gfc, "frames=%d\n", gfc->ov_enc.frame_number); + MSGF(gfc, "pcm_samples_per_frame=%d\n", pcm_samples_per_frame); + MSGF(gfc, "encoder delay=%d\n", ed); + MSGF(gfc, "encoder padding=%d\n", ep); + MSGF(gfc, "sample count=%d (%g)\n", ns, cfg->samplerate_in * duration); + MSGF(gfc, "duration=%g sec\n", duration); + } +#endif + return mp3count; +} + +/*********************************************************************** + * + * lame_close () + * + * frees internal buffers + * + ***********************************************************************/ + +int +lame_close(lame_global_flags * gfp) +{ + int ret = 0; + if (gfp && gfp->class_id == LAME_ID) { + lame_internal_flags *const gfc = gfp->internal_flags; + gfp->class_id = 0; + if (NULL == gfc || gfc->class_id != LAME_ID) { + ret = -3; + } + if (NULL != gfc) { + gfc->lame_init_params_successful = 0; + gfc->class_id = 0; + /* this routine will free all malloc'd data in gfc, and then free gfc: */ + freegfc(gfc); + gfp->internal_flags = NULL; + } + if (gfp->lame_allocated_gfp) { + gfp->lame_allocated_gfp = 0; + free(gfp); + } + } + return ret; +} + +/*****************************************************************/ +/* flush internal mp3 buffers, and free internal buffers */ +/*****************************************************************/ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +int CDECL +lame_encode_finish(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size); +#else +#endif + +int +lame_encode_finish(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size) +{ + int const ret = lame_encode_flush(gfp, mp3buffer, mp3buffer_size); + + (void) lame_close(gfp); + + return ret; +} + +/*****************************************************************/ +/* write VBR Xing header, and ID3 version 1 tag, if asked for */ +/*****************************************************************/ +void lame_mp3_tags_fid(lame_global_flags * gfp, FILE * fpStream); + +void +lame_mp3_tags_fid(lame_global_flags * gfp, FILE * fpStream) +{ + lame_internal_flags *gfc; + SessionConfig_t const *cfg; + if (!is_lame_global_flags_valid(gfp)) { + return; + } + gfc = gfp->internal_flags; + if (!is_lame_internal_flags_valid(gfc)) { + return; + } + cfg = &gfc->cfg; + if (!cfg->write_lame_tag) { + return; + } + /* Write Xing header again */ + if (fpStream && !fseek(fpStream, 0, SEEK_SET)) { + int rc = PutVbrTag(gfp, fpStream); + switch (rc) { + default: + /* OK */ + break; + + case -1: + ERRORF(gfc, "Error: could not update LAME tag.\n"); + break; + + case -2: + ERRORF(gfc, "Error: could not update LAME tag, file not seekable.\n"); + break; + + case -3: + ERRORF(gfc, "Error: could not update LAME tag, file not readable.\n"); + break; + } + } +} + + +static int +lame_init_internal_flags(lame_internal_flags* gfc) +{ + if (NULL == gfc) + return -1; + + gfc->cfg.vbr_min_bitrate_index = 1; /* not 0 ????? */ + gfc->cfg.vbr_max_bitrate_index = 13; /* not 14 ????? */ + gfc->cfg.decode_on_the_fly = 0; + gfc->cfg.findReplayGain = 0; + gfc->cfg.findPeakSample = 0; + + gfc->sv_qnt.OldValue[0] = 180; + gfc->sv_qnt.OldValue[1] = 180; + gfc->sv_qnt.CurrentStep[0] = 4; + gfc->sv_qnt.CurrentStep[1] = 4; + gfc->sv_qnt.masking_lower = 1; + + /* The reason for + * int mf_samples_to_encode = ENCDELAY + POSTDELAY; + * ENCDELAY = internal encoder delay. And then we have to add POSTDELAY=288 + * because of the 50% MDCT overlap. A 576 MDCT granule decodes to + * 1152 samples. To synthesize the 576 samples centered under this granule + * we need the previous granule for the first 288 samples (no problem), and + * the next granule for the next 288 samples (not possible if this is last + * granule). So we need to pad with 288 samples to make sure we can + * encode the 576 samples we are interested in. + */ + gfc->sv_enc.mf_samples_to_encode = ENCDELAY + POSTDELAY; + gfc->sv_enc.mf_size = ENCDELAY - MDCTDELAY; /* we pad input with this many 0's */ + gfc->ov_enc.encoder_padding = 0; + gfc->ov_enc.encoder_delay = ENCDELAY; + + gfc->ov_rpg.RadioGain = 0; + gfc->ov_rpg.noclipGainChange = 0; + gfc->ov_rpg.noclipScale = -1.0; + + gfc->ATH = lame_calloc(ATH_t, 1); + if (NULL == gfc->ATH) + return -2; /* maybe error codes should be enumerated in lame.h ?? */ + + gfc->sv_rpg.rgdata = lame_calloc(replaygain_t, 1); + if (NULL == gfc->sv_rpg.rgdata) { + return -2; + } + return 0; +} + +/* initialize mp3 encoder */ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +static +#else +#endif +int +lame_init_old(lame_global_flags * gfp) +{ + disable_FPE(); /* disable floating point exceptions */ + + memset(gfp, 0, sizeof(lame_global_flags)); + + gfp->class_id = LAME_ID; + + /* Global flags. set defaults here for non-zero values */ + /* see lame.h for description */ + /* set integer values to -1 to mean that LAME will compute the + * best value, UNLESS the calling program as set it + * (and the value is no longer -1) + */ + gfp->strict_ISO = MDB_MAXIMUM; + + gfp->mode = NOT_SET; + gfp->original = 1; + gfp->samplerate_in = 44100; + gfp->num_channels = 2; + gfp->num_samples = MAX_U_32_NUM; + + gfp->write_lame_tag = 1; + gfp->quality = -1; + gfp->short_blocks = short_block_not_set; + gfp->subblock_gain = -1; + + gfp->lowpassfreq = 0; + gfp->highpassfreq = 0; + gfp->lowpasswidth = -1; + gfp->highpasswidth = -1; + + gfp->VBR = vbr_off; + gfp->VBR_q = 4; + gfp->VBR_mean_bitrate_kbps = 128; + gfp->VBR_min_bitrate_kbps = 0; + gfp->VBR_max_bitrate_kbps = 0; + gfp->VBR_hard_min = 0; + + gfp->quant_comp = -1; + gfp->quant_comp_short = -1; + + gfp->msfix = -1; + + gfp->attackthre = -1; + gfp->attackthre_s = -1; + + gfp->scale = 1; + gfp->scale_left = 1; + gfp->scale_right = 1; + + gfp->ATHcurve = -1; + gfp->ATHtype = -1; /* default = -1 = set in lame_init_params */ + /* 2 = equal loudness curve */ + gfp->athaa_sensitivity = 0.0; /* no offset */ + gfp->athaa_type = -1; + gfp->useTemporal = -1; + gfp->interChRatio = -1; + + gfp->findReplayGain = 0; + gfp->decode_on_the_fly = 0; + + gfp->asm_optimizations.mmx = 1; + gfp->asm_optimizations.amd3dnow = 1; + gfp->asm_optimizations.sse = 1; + + gfp->preset = 0; + + gfp->write_id3tag_automatic = 1; + + gfp->report.debugf = &lame_report_def; + gfp->report.errorf = &lame_report_def; + gfp->report.msgf = &lame_report_def; + + gfp->internal_flags = lame_calloc(lame_internal_flags, 1); + + if (lame_init_internal_flags(gfp->internal_flags) < 0) { + freegfc(gfp->internal_flags); + gfp->internal_flags = 0; + return -1; + } + return 0; +} + + +lame_global_flags * +lame_init(void) +{ + lame_global_flags *gfp; + int ret; + + init_log_table(); + + gfp = lame_calloc(lame_global_flags, 1); + if (gfp == NULL) + return NULL; + + ret = lame_init_old(gfp); + if (ret != 0) { + free(gfp); + return NULL; + } + + gfp->lame_allocated_gfp = 1; + return gfp; +} + + +/*********************************************************************** + * + * some simple statistics + * + * Robert Hegemann 2000-10-11 + * + ***********************************************************************/ + +/* histogram of used bitrate indexes: + * One has to weight them to calculate the average bitrate in kbps + * + * bitrate indices: + * there are 14 possible bitrate indices, 0 has the special meaning + * "free format" which is not possible to mix with VBR and 15 is forbidden + * anyway. + * + * stereo modes: + * 0: LR number of left-right encoded frames + * 1: LR-I number of left-right and intensity encoded frames + * 2: MS number of mid-side encoded frames + * 3: MS-I number of mid-side and intensity encoded frames + * + * 4: number of encoded frames + * + */ + +void +lame_bitrate_kbps(const lame_global_flags * gfp, int bitrate_kbps[14]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + int i; + if (cfg->free_format) { + for (i = 0; i < 14; i++) + bitrate_kbps[i] = -1; + bitrate_kbps[0] = cfg->avg_bitrate; + } + else { + for (i = 0; i < 14; i++) + bitrate_kbps[i] = bitrate_table[cfg->version][i + 1]; + } + } + } +} + + +void +lame_bitrate_hist(const lame_global_flags * gfp, int bitrate_count[14]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int i; + + if (cfg->free_format) { + for (i = 0; i < 14; i++) { + bitrate_count[i] = 0; + } + bitrate_count[0] = eov->bitrate_channelmode_hist[0][4]; + } + else { + for (i = 0; i < 14; i++) { + bitrate_count[i] = eov->bitrate_channelmode_hist[i + 1][4]; + } + } + } + } +} + + +void +lame_stereo_mode_hist(const lame_global_flags * gfp, int stmode_count[4]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + EncResult_t const *const eov = &gfc->ov_enc; + int i; + + for (i = 0; i < 4; i++) { + stmode_count[i] = eov->bitrate_channelmode_hist[15][i]; + } + } + } +} + + + +void +lame_bitrate_stereo_mode_hist(const lame_global_flags * gfp, int bitrate_stmode_count[14][4]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int i; + int j; + + if (cfg->free_format) { + for (j = 0; j < 14; j++) + for (i = 0; i < 4; i++) { + bitrate_stmode_count[j][i] = 0; + } + for (i = 0; i < 4; i++) { + bitrate_stmode_count[0][i] = eov->bitrate_channelmode_hist[0][i]; + } + } + else { + for (j = 0; j < 14; j++) { + for (i = 0; i < 4; i++) { + bitrate_stmode_count[j][i] = eov->bitrate_channelmode_hist[j + 1][i]; + } + } + } + } + } +} + + +void +lame_block_type_hist(const lame_global_flags * gfp, int btype_count[6]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + EncResult_t const *const eov = &gfc->ov_enc; + int i; + + for (i = 0; i < 6; ++i) { + btype_count[i] = eov->bitrate_blocktype_hist[15][i]; + } + } + } +} + + + +void +lame_bitrate_block_type_hist(const lame_global_flags * gfp, int bitrate_btype_count[14][6]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int i, j; + + if (cfg->free_format) { + for (j = 0; j < 14; ++j) { + for (i = 0; i < 6; ++i) { + bitrate_btype_count[j][i] = 0; + } + } + for (i = 0; i < 6; ++i) { + bitrate_btype_count[0][i] = eov->bitrate_blocktype_hist[0][i]; + } + } + else { + for (j = 0; j < 14; ++j) { + for (i = 0; i < 6; ++i) { + bitrate_btype_count[j][i] = eov->bitrate_blocktype_hist[j + 1][i]; + } + } + } + } + } +} + +/* end of lame.c */ diff --git a/pkg/lame/clame/lame.h b/pkg/lame/clame/lame.h new file mode 100644 index 0000000..5196690 --- /dev/null +++ b/pkg/lame/clame/lame.h @@ -0,0 +1,1342 @@ +/* + * Interface to MP3 LAME encoding engine + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: lame.h,v 1.192 2017/08/31 14:14:46 robert Exp $ */ + +#ifndef LAME_LAME_H +#define LAME_LAME_H + +/* for size_t typedef */ +#include +/* for va_list typedef */ +#include +/* for FILE typedef, TODO: remove when removing lame_mp3_tags_fid */ +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef void (*lame_report_function)(const char *format, va_list ap); + +#if defined(WIN32) || defined(_WIN32) +#undef CDECL +#define CDECL __cdecl +#else +#define CDECL +#endif + +#define DEPRECATED_OR_OBSOLETE_CODE_REMOVED 1 + +typedef enum vbr_mode_e { + vbr_off=0, + vbr_mt, /* obsolete, same as vbr_mtrh */ + vbr_rh, + vbr_abr, + vbr_mtrh, + vbr_max_indicator, /* Don't use this! It's used for sanity checks. */ + vbr_default=vbr_mtrh /* change this to change the default VBR mode of LAME */ +} vbr_mode; + + +/* MPEG modes */ +typedef enum MPEG_mode_e { + STEREO = 0, + JOINT_STEREO, + DUAL_CHANNEL, /* LAME doesn't supports this! */ + MONO, + NOT_SET, + MAX_INDICATOR /* Don't use this! It's used for sanity checks. */ +} MPEG_mode; + +/* Padding types */ +typedef enum Padding_type_e { + PAD_NO = 0, + PAD_ALL, + PAD_ADJUST, + PAD_MAX_INDICATOR /* Don't use this! It's used for sanity checks. */ +} Padding_type; + + + +/*presets*/ +typedef enum preset_mode_e { + /*values from 8 to 320 should be reserved for abr bitrates*/ + /*for abr I'd suggest to directly use the targeted bitrate as a value*/ + ABR_8 = 8, + ABR_320 = 320, + + V9 = 410, /*Vx to match Lame and VBR_xx to match FhG*/ + VBR_10 = 410, + V8 = 420, + VBR_20 = 420, + V7 = 430, + VBR_30 = 430, + V6 = 440, + VBR_40 = 440, + V5 = 450, + VBR_50 = 450, + V4 = 460, + VBR_60 = 460, + V3 = 470, + VBR_70 = 470, + V2 = 480, + VBR_80 = 480, + V1 = 490, + VBR_90 = 490, + V0 = 500, + VBR_100 = 500, + + + + /*still there for compatibility*/ + R3MIX = 1000, + STANDARD = 1001, + EXTREME = 1002, + INSANE = 1003, + STANDARD_FAST = 1004, + EXTREME_FAST = 1005, + MEDIUM = 1006, + MEDIUM_FAST = 1007 +} preset_mode; + + +/*asm optimizations*/ +typedef enum asm_optimizations_e { + MMX = 1, + AMD_3DNOW = 2, + SSE = 3 +} asm_optimizations; + + +/* psychoacoustic model */ +typedef enum Psy_model_e { + PSY_GPSYCHO = 1, + PSY_NSPSYTUNE = 2 +} Psy_model; + + +/* buffer considerations */ +typedef enum buffer_constraint_e { + MDB_DEFAULT=0, + MDB_STRICT_ISO=1, + MDB_MAXIMUM=2 +} buffer_constraint; + + +struct lame_global_struct; +typedef struct lame_global_struct lame_global_flags; +typedef lame_global_flags *lame_t; + + + + +/*********************************************************************** + * + * The LAME API + * These functions should be called, in this order, for each + * MP3 file to be encoded. See the file "API" for more documentation + * + ***********************************************************************/ + + +/* + * REQUIRED: + * initialize the encoder. sets default for all encoder parameters, + * returns NULL if some malloc()'s failed + * otherwise returns pointer to structure needed for all future + * API calls. + */ +lame_global_flags * CDECL lame_init(void); +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* obsolete version */ +int CDECL lame_init_old(lame_global_flags *); +#endif + +/* + * OPTIONAL: + * set as needed to override defaults + */ + +/******************************************************************** + * input stream description + ***********************************************************************/ +/* number of samples. default = 2^32-1 */ +int CDECL lame_set_num_samples(lame_global_flags *, unsigned long); +unsigned long CDECL lame_get_num_samples(const lame_global_flags *); + +/* input sample rate in Hz. default = 44100hz */ +int CDECL lame_set_in_samplerate(lame_global_flags *, int); +int CDECL lame_get_in_samplerate(const lame_global_flags *); + +/* number of channels in input stream. default=2 */ +int CDECL lame_set_num_channels(lame_global_flags *, int); +int CDECL lame_get_num_channels(const lame_global_flags *); + +/* + scale the input by this amount before encoding. default=1 + (not used by decoding routines) +*/ +int CDECL lame_set_scale(lame_global_flags *, float); +float CDECL lame_get_scale(const lame_global_flags *); + +/* + scale the channel 0 (left) input by this amount before encoding. default=1 + (not used by decoding routines) +*/ +int CDECL lame_set_scale_left(lame_global_flags *, float); +float CDECL lame_get_scale_left(const lame_global_flags *); + +/* + scale the channel 1 (right) input by this amount before encoding. default=1 + (not used by decoding routines) +*/ +int CDECL lame_set_scale_right(lame_global_flags *, float); +float CDECL lame_get_scale_right(const lame_global_flags *); + +/* + output sample rate in Hz. default = 0, which means LAME picks best value + based on the amount of compression. MPEG only allows: + MPEG1 32, 44.1, 48khz + MPEG2 16, 22.05, 24 + MPEG2.5 8, 11.025, 12 + (not used by decoding routines) +*/ +int CDECL lame_set_out_samplerate(lame_global_flags *, int); +int CDECL lame_get_out_samplerate(const lame_global_flags *); + + +/******************************************************************** + * general control parameters + ***********************************************************************/ +/* 1=cause LAME to collect data for an MP3 frame analyzer. default=0 */ +int CDECL lame_set_analysis(lame_global_flags *, int); +int CDECL lame_get_analysis(const lame_global_flags *); + +/* + 1 = write a Xing VBR header frame. + default = 1 + this variable must have been added by a Hungarian notation Windows programmer :-) +*/ +int CDECL lame_set_bWriteVbrTag(lame_global_flags *, int); +int CDECL lame_get_bWriteVbrTag(const lame_global_flags *); + +/* 1=decode only. use lame/mpglib to convert mp3/ogg to wav. default=0 */ +int CDECL lame_set_decode_only(lame_global_flags *, int); +int CDECL lame_get_decode_only(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* 1=encode a Vorbis .ogg file. default=0 */ +/* DEPRECATED */ +int CDECL lame_set_ogg(lame_global_flags *, int); +int CDECL lame_get_ogg(const lame_global_flags *); +#endif + +/* + internal algorithm selection. True quality is determined by the bitrate + but this variable will effect quality by selecting expensive or cheap algorithms. + quality=0..9. 0=best (very slow). 9=worst. + recommended: 2 near-best quality, not too slow + 5 good quality, fast + 7 ok quality, really fast +*/ +int CDECL lame_set_quality(lame_global_flags *, int); +int CDECL lame_get_quality(const lame_global_flags *); + +/* + mode = 0,1,2,3 = stereo, jstereo, dual channel (not supported), mono + default: lame picks based on compression ration and input channels +*/ +int CDECL lame_set_mode(lame_global_flags *, MPEG_mode); +MPEG_mode CDECL lame_get_mode(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* + mode_automs. Use a M/S mode with a switching threshold based on + compression ratio + DEPRECATED +*/ +int CDECL lame_set_mode_automs(lame_global_flags *, int); +int CDECL lame_get_mode_automs(const lame_global_flags *); +#endif + +/* + force_ms. Force M/S for all frames. For testing only. + default = 0 (disabled) +*/ +int CDECL lame_set_force_ms(lame_global_flags *, int); +int CDECL lame_get_force_ms(const lame_global_flags *); + +/* use free_format? default = 0 (disabled) */ +int CDECL lame_set_free_format(lame_global_flags *, int); +int CDECL lame_get_free_format(const lame_global_flags *); + +/* perform ReplayGain analysis? default = 0 (disabled) */ +int CDECL lame_set_findReplayGain(lame_global_flags *, int); +int CDECL lame_get_findReplayGain(const lame_global_flags *); + +/* decode on the fly. Search for the peak sample. If the ReplayGain + * analysis is enabled then perform the analysis on the decoded data + * stream. default = 0 (disabled) + * NOTE: if this option is set the build-in decoder should not be used */ +int CDECL lame_set_decode_on_the_fly(lame_global_flags *, int); +int CDECL lame_get_decode_on_the_fly(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* DEPRECATED: now does the same as lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_input(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_input(const lame_global_flags *); + +/* DEPRECATED: now does the same as + lame_set_decode_on_the_fly() && lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_decode(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_decode(const lame_global_flags *); + +/* DEPRECATED: now does the same as lame_set_decode_on_the_fly() + default = 0 (disabled) */ +int CDECL lame_set_findPeakSample(lame_global_flags *, int); +int CDECL lame_get_findPeakSample(const lame_global_flags *); +#endif + +/* counters for gapless encoding */ +int CDECL lame_set_nogap_total(lame_global_flags*, int); +int CDECL lame_get_nogap_total(const lame_global_flags*); + +int CDECL lame_set_nogap_currentindex(lame_global_flags* , int); +int CDECL lame_get_nogap_currentindex(const lame_global_flags*); + + +/* + * OPTIONAL: + * Set printf like error/debug/message reporting functions. + * The second argument has to be a pointer to a function which looks like + * void my_debugf(const char *format, va_list ap) + * { + * (void) vfprintf(stdout, format, ap); + * } + * If you use NULL as the value of the pointer in the set function, the + * lame buildin function will be used (prints to stderr). + * To quiet any output you have to replace the body of the example function + * with just "return;" and use it in the set function. + */ +int CDECL lame_set_errorf(lame_global_flags *, lame_report_function); +int CDECL lame_set_debugf(lame_global_flags *, lame_report_function); +int CDECL lame_set_msgf (lame_global_flags *, lame_report_function); + + + +/* set one of brate compression ratio. default is compression ratio of 11. */ +int CDECL lame_set_brate(lame_global_flags *, int); +int CDECL lame_get_brate(const lame_global_flags *); +int CDECL lame_set_compression_ratio(lame_global_flags *, float); +float CDECL lame_get_compression_ratio(const lame_global_flags *); + + +int CDECL lame_set_preset( lame_global_flags* gfp, int ); +int CDECL lame_set_asm_optimizations( lame_global_flags* gfp, int, int ); + + + +/******************************************************************** + * frame params + ***********************************************************************/ +/* mark as copyright. default=0 */ +int CDECL lame_set_copyright(lame_global_flags *, int); +int CDECL lame_get_copyright(const lame_global_flags *); + +/* mark as original. default=1 */ +int CDECL lame_set_original(lame_global_flags *, int); +int CDECL lame_get_original(const lame_global_flags *); + +/* error_protection. Use 2 bytes from each frame for CRC checksum. default=0 */ +int CDECL lame_set_error_protection(lame_global_flags *, int); +int CDECL lame_get_error_protection(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* padding_type. 0=pad no frames 1=pad all frames 2=adjust padding(default) */ +int CDECL lame_set_padding_type(lame_global_flags *, Padding_type); +Padding_type CDECL lame_get_padding_type(const lame_global_flags *); +#endif + +/* MP3 'private extension' bit Meaningless. default=0 */ +int CDECL lame_set_extension(lame_global_flags *, int); +int CDECL lame_get_extension(const lame_global_flags *); + +/* enforce strict ISO compliance. default=0 */ +int CDECL lame_set_strict_ISO(lame_global_flags *, int); +int CDECL lame_get_strict_ISO(const lame_global_flags *); + + +/******************************************************************** + * quantization/noise shaping + ***********************************************************************/ + +/* disable the bit reservoir. For testing only. default=0 */ +int CDECL lame_set_disable_reservoir(lame_global_flags *, int); +int CDECL lame_get_disable_reservoir(const lame_global_flags *); + +/* select a different "best quantization" function. default=0 */ +int CDECL lame_set_quant_comp(lame_global_flags *, int); +int CDECL lame_get_quant_comp(const lame_global_flags *); +int CDECL lame_set_quant_comp_short(lame_global_flags *, int); +int CDECL lame_get_quant_comp_short(const lame_global_flags *); + +int CDECL lame_set_experimentalX(lame_global_flags *, int); /* compatibility*/ +int CDECL lame_get_experimentalX(const lame_global_flags *); + +/* another experimental option. for testing only */ +int CDECL lame_set_experimentalY(lame_global_flags *, int); +int CDECL lame_get_experimentalY(const lame_global_flags *); + +/* another experimental option. for testing only */ +int CDECL lame_set_experimentalZ(lame_global_flags *, int); +int CDECL lame_get_experimentalZ(const lame_global_flags *); + +/* Naoki's psycho acoustic model. default=0 */ +int CDECL lame_set_exp_nspsytune(lame_global_flags *, int); +int CDECL lame_get_exp_nspsytune(const lame_global_flags *); + +void CDECL lame_set_msfix(lame_global_flags *, double); +float CDECL lame_get_msfix(const lame_global_flags *); + + +/******************************************************************** + * VBR control + ***********************************************************************/ +/* Types of VBR. default = vbr_off = CBR */ +int CDECL lame_set_VBR(lame_global_flags *, vbr_mode); +vbr_mode CDECL lame_get_VBR(const lame_global_flags *); + +/* VBR quality level. 0=highest 9=lowest */ +int CDECL lame_set_VBR_q(lame_global_flags *, int); +int CDECL lame_get_VBR_q(const lame_global_flags *); + +/* VBR quality level. 0=highest 9=lowest, Range [0,...,10[ */ +int CDECL lame_set_VBR_quality(lame_global_flags *, float); +float CDECL lame_get_VBR_quality(const lame_global_flags *); + +/* Ignored except for VBR=vbr_abr (ABR mode) */ +int CDECL lame_set_VBR_mean_bitrate_kbps(lame_global_flags *, int); +int CDECL lame_get_VBR_mean_bitrate_kbps(const lame_global_flags *); + +int CDECL lame_set_VBR_min_bitrate_kbps(lame_global_flags *, int); +int CDECL lame_get_VBR_min_bitrate_kbps(const lame_global_flags *); + +int CDECL lame_set_VBR_max_bitrate_kbps(lame_global_flags *, int); +int CDECL lame_get_VBR_max_bitrate_kbps(const lame_global_flags *); + +/* + 1=strictly enforce VBR_min_bitrate. Normally it will be violated for + analog silence +*/ +int CDECL lame_set_VBR_hard_min(lame_global_flags *, int); +int CDECL lame_get_VBR_hard_min(const lame_global_flags *); + +/* for preset */ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +int CDECL lame_set_preset_expopts(lame_global_flags *, int); +#endif + +/******************************************************************** + * Filtering control + ***********************************************************************/ +/* freq in Hz to apply lowpass. Default = 0 = lame chooses. -1 = disabled */ +int CDECL lame_set_lowpassfreq(lame_global_flags *, int); +int CDECL lame_get_lowpassfreq(const lame_global_flags *); +/* width of transition band, in Hz. Default = one polyphase filter band */ +int CDECL lame_set_lowpasswidth(lame_global_flags *, int); +int CDECL lame_get_lowpasswidth(const lame_global_flags *); + +/* freq in Hz to apply highpass. Default = 0 = lame chooses. -1 = disabled */ +int CDECL lame_set_highpassfreq(lame_global_flags *, int); +int CDECL lame_get_highpassfreq(const lame_global_flags *); +/* width of transition band, in Hz. Default = one polyphase filter band */ +int CDECL lame_set_highpasswidth(lame_global_flags *, int); +int CDECL lame_get_highpasswidth(const lame_global_flags *); + + +/******************************************************************** + * psycho acoustics and other arguments which you should not change + * unless you know what you are doing + ***********************************************************************/ + +/* only use ATH for masking */ +int CDECL lame_set_ATHonly(lame_global_flags *, int); +int CDECL lame_get_ATHonly(const lame_global_flags *); + +/* only use ATH for short blocks */ +int CDECL lame_set_ATHshort(lame_global_flags *, int); +int CDECL lame_get_ATHshort(const lame_global_flags *); + +/* disable ATH */ +int CDECL lame_set_noATH(lame_global_flags *, int); +int CDECL lame_get_noATH(const lame_global_flags *); + +/* select ATH formula */ +int CDECL lame_set_ATHtype(lame_global_flags *, int); +int CDECL lame_get_ATHtype(const lame_global_flags *); + +/* lower ATH by this many db */ +int CDECL lame_set_ATHlower(lame_global_flags *, float); +float CDECL lame_get_ATHlower(const lame_global_flags *); + +/* select ATH adaptive adjustment type */ +int CDECL lame_set_athaa_type( lame_global_flags *, int); +int CDECL lame_get_athaa_type( const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* select the loudness approximation used by the ATH adaptive auto-leveling */ +int CDECL lame_set_athaa_loudapprox( lame_global_flags *, int); +int CDECL lame_get_athaa_loudapprox( const lame_global_flags *); +#endif + +/* adjust (in dB) the point below which adaptive ATH level adjustment occurs */ +int CDECL lame_set_athaa_sensitivity( lame_global_flags *, float); +float CDECL lame_get_athaa_sensitivity( const lame_global_flags* ); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* OBSOLETE: predictability limit (ISO tonality formula) */ +int CDECL lame_set_cwlimit(lame_global_flags *, int); +int CDECL lame_get_cwlimit(const lame_global_flags *); +#endif + +/* + allow blocktypes to differ between channels? + default: 0 for jstereo, 1 for stereo +*/ +int CDECL lame_set_allow_diff_short(lame_global_flags *, int); +int CDECL lame_get_allow_diff_short(const lame_global_flags *); + +/* use temporal masking effect (default = 1) */ +int CDECL lame_set_useTemporal(lame_global_flags *, int); +int CDECL lame_get_useTemporal(const lame_global_flags *); + +/* use temporal masking effect (default = 1) */ +int CDECL lame_set_interChRatio(lame_global_flags *, float); +float CDECL lame_get_interChRatio(const lame_global_flags *); + +/* disable short blocks */ +int CDECL lame_set_no_short_blocks(lame_global_flags *, int); +int CDECL lame_get_no_short_blocks(const lame_global_flags *); + +/* force short blocks */ +int CDECL lame_set_force_short_blocks(lame_global_flags *, int); +int CDECL lame_get_force_short_blocks(const lame_global_flags *); + +/* Input PCM is emphased PCM (for instance from one of the rarely + emphased CDs), it is STRONGLY not recommended to use this, because + psycho does not take it into account, and last but not least many decoders + ignore these bits */ +int CDECL lame_set_emphasis(lame_global_flags *, int); +int CDECL lame_get_emphasis(const lame_global_flags *); + + + +/************************************************************************/ +/* internal variables, cannot be set... */ +/* provided because they may be of use to calling application */ +/************************************************************************/ +/* version 0=MPEG-2 1=MPEG-1 (2=MPEG-2.5) */ +int CDECL lame_get_version(const lame_global_flags *); + +/* encoder delay */ +int CDECL lame_get_encoder_delay(const lame_global_flags *); + +/* + padding appended to the input to make sure decoder can fully decode + all input. Note that this value can only be calculated during the + call to lame_encoder_flush(). Before lame_encoder_flush() has + been called, the value of encoder_padding = 0. +*/ +int CDECL lame_get_encoder_padding(const lame_global_flags *); + +/* size of MPEG frame */ +int CDECL lame_get_framesize(const lame_global_flags *); + +/* number of PCM samples buffered, but not yet encoded to mp3 data. */ +int CDECL lame_get_mf_samples_to_encode( const lame_global_flags* gfp ); + +/* + size (bytes) of mp3 data buffered, but not yet encoded. + this is the number of bytes which would be output by a call to + lame_encode_flush_nogap. NOTE: lame_encode_flush() will return + more bytes than this because it will encode the reamining buffered + PCM samples before flushing the mp3 buffers. +*/ +int CDECL lame_get_size_mp3buffer( const lame_global_flags* gfp ); + +/* number of frames encoded so far */ +int CDECL lame_get_frameNum(const lame_global_flags *); + +/* + lame's estimate of the total number of frames to be encoded + only valid if calling program set num_samples +*/ +int CDECL lame_get_totalframes(const lame_global_flags *); + +/* RadioGain value. Multiplied by 10 and rounded to the nearest. */ +int CDECL lame_get_RadioGain(const lame_global_flags *); + +/* AudiophileGain value. Multipled by 10 and rounded to the nearest. */ +int CDECL lame_get_AudiophileGain(const lame_global_flags *); + +/* the peak sample */ +float CDECL lame_get_PeakSample(const lame_global_flags *); + +/* Gain change required for preventing clipping. The value is correct only if + peak sample searching was enabled. If negative then the waveform + already does not clip. The value is multiplied by 10 and rounded up. */ +int CDECL lame_get_noclipGainChange(const lame_global_flags *); + +/* user-specified scale factor required for preventing clipping. Value is + correct only if peak sample searching was enabled and no user-specified + scaling was performed. If negative then either the waveform already does + not clip or the value cannot be determined */ +float CDECL lame_get_noclipScale(const lame_global_flags *); + +/* returns the limit of PCM samples, which one can pass in an encode call + under the constrain of a provided buffer of size buffer_size */ +int CDECL lame_get_maximum_number_of_samples(lame_t gfp, size_t buffer_size); + + + + +/* + * REQUIRED: + * sets more internal configuration based on data provided above. + * returns -1 if something failed. + */ +int CDECL lame_init_params(lame_global_flags *); + + +/* + * OPTIONAL: + * get the version number, in a string. of the form: + * "3.63 (beta)" or just "3.63". + */ +const char* CDECL get_lame_version ( void ); +const char* CDECL get_lame_short_version ( void ); +const char* CDECL get_lame_very_short_version ( void ); +const char* CDECL get_psy_version ( void ); +const char* CDECL get_lame_url ( void ); +const char* CDECL get_lame_os_bitness ( void ); + +/* + * OPTIONAL: + * get the version numbers in numerical form. + */ +typedef struct { + /* generic LAME version */ + int major; + int minor; + int alpha; /* 0 if not an alpha version */ + int beta; /* 0 if not a beta version */ + + /* version of the psy model */ + int psy_major; + int psy_minor; + int psy_alpha; /* 0 if not an alpha version */ + int psy_beta; /* 0 if not a beta version */ + + /* compile time features */ + const char *features; /* Don't make assumptions about the contents! */ +} lame_version_t; +void CDECL get_lame_version_numerical(lame_version_t *); + + +/* + * OPTIONAL: + * print internal lame configuration to message handler + */ +void CDECL lame_print_config(const lame_global_flags* gfp); + +void CDECL lame_print_internals( const lame_global_flags *gfp); + + +/* + * input pcm data, output (maybe) mp3 frames. + * This routine handles all buffering, resampling and filtering for you. + * + * return code number of bytes output in mp3buf. Can be 0 + * -1: mp3buf was too small + * -2: malloc() problem + * -3: lame_init_params() not called + * -4: psycho acoustic problems + * + * The required mp3buf_size can be computed from num_samples, + * samplerate and encoding rate, but here is a worst case estimate: + * + * mp3buf_size in bytes = 1.25*num_samples + 7200 + * + * I think a tighter bound could be: (mt, March 2000) + * MPEG1: + * num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512 + * MPEG2: + * num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256 + * + * but test first if you use that! + * + * set mp3buf_size = 0 and LAME will not check if mp3buf_size is + * large enough. + * + * NOTE: + * if gfp->num_channels=2, but gfp->mode = 3 (mono), the L & R channels + * will be averaged into the L channel before encoding only the L channel + * This will overwrite the data in buffer_l[] and buffer_r[]. + * +*/ +int CDECL lame_encode_buffer ( + lame_global_flags* gfp, /* global context handle */ + const short int buffer_l [], /* PCM data for left channel */ + const short int buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* + * as above, but input has L & R channel data interleaved. + * NOTE: + * num_samples = number of samples in the L (or R) + * channel, not the total number of samples in pcm[] + */ +int CDECL lame_encode_buffer_interleaved( + lame_global_flags* gfp, /* global context handlei */ + short int pcm[], /* PCM data for left and right + channel, interleaved */ + int num_samples, /* number of samples per channel, + _not_ number of samples in + pcm[] */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int mp3buf_size ); /* number of valid octets in this + stream */ + + +/* as lame_encode_buffer, but for 'float's. + * !! NOTE: !! data must still be scaled to be in the same range as + * short int, +/- 32768 + */ +int CDECL lame_encode_buffer_float( + lame_global_flags* gfp, /* global context handle */ + const float pcm_l [], /* PCM data for left channel */ + const float pcm_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* as lame_encode_buffer, but for 'float's. + * !! NOTE: !! data must be scaled to +/- 1 full scale + */ +int CDECL lame_encode_buffer_ieee_float( + lame_t gfp, + const float pcm_l [], /* PCM data for left channel */ + const float pcm_r [], /* PCM data for right channel */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); +int CDECL lame_encode_buffer_interleaved_ieee_float( + lame_t gfp, + const float pcm[], /* PCM data for left and right + channel, interleaved */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); + +/* as lame_encode_buffer, but for 'double's. + * !! NOTE: !! data must be scaled to +/- 1 full scale + */ +int CDECL lame_encode_buffer_ieee_double( + lame_t gfp, + const double pcm_l [], /* PCM data for left channel */ + const double pcm_r [], /* PCM data for right channel */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); +int CDECL lame_encode_buffer_interleaved_ieee_double( + lame_t gfp, + const double pcm[], /* PCM data for left and right + channel, interleaved */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); + +/* as lame_encode_buffer, but for long's + * !! NOTE: !! data must still be scaled to be in the same range as + * short int, +/- 32768 + * + * This scaling was a mistake (doesn't allow one to exploit full + * precision of type 'long'. Use lame_encode_buffer_long2() instead. + * + */ +int CDECL lame_encode_buffer_long( + lame_global_flags* gfp, /* global context handle */ + const long buffer_l [], /* PCM data for left channel */ + const long buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* Same as lame_encode_buffer_long(), but with correct scaling. + * !! NOTE: !! data must still be scaled to be in the same range as + * type 'long'. Data should be in the range: +/- 2^(8*size(long)-1) + * + */ +int CDECL lame_encode_buffer_long2( + lame_global_flags* gfp, /* global context handle */ + const long buffer_l [], /* PCM data for left channel */ + const long buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* as lame_encode_buffer, but for int's + * !! NOTE: !! input should be scaled to the maximum range of 'int' + * If int is 4 bytes, then the values should range from + * +/- 2147483648. + * + * This routine does not (and cannot, without loosing precision) use + * the same scaling as the rest of the lame_encode_buffer() routines. + * + */ +int CDECL lame_encode_buffer_int( + lame_global_flags* gfp, /* global context handle */ + const int buffer_l [], /* PCM data for left channel */ + const int buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* + * as above, but for interleaved data. + * !! NOTE: !! data must still be scaled to be in the same range as + * type 'int32_t'. Data should be in the range: +/- 2^(8*size(int32_t)-1) + * NOTE: + * num_samples = number of samples in the L (or R) + * channel, not the total number of samples in pcm[] + */ +int +lame_encode_buffer_interleaved_int( + lame_t gfp, + const int pcm [], /* PCM data for left and right + channel, interleaved */ + const int nsamples, /* number of samples per channel, + _not_ number of samples in + pcm[] */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + + + +/* + * REQUIRED: + * lame_encode_flush will flush the intenal PCM buffers, padding with + * 0's to make sure the final frame is complete, and then flush + * the internal MP3 buffers, and thus may return a + * final few mp3 frames. 'mp3buf' should be at least 7200 bytes long + * to hold all possible emitted data. + * + * will also write id3v1 tags (if any) into the bitstream + * + * return code = number of bytes output to mp3buf. Can be 0 + */ +int CDECL lame_encode_flush( + lame_global_flags * gfp, /* global context handle */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int size); /* number of valid octets in this stream */ + +/* + * OPTIONAL: + * lame_encode_flush_nogap will flush the internal mp3 buffers and pad + * the last frame with ancillary data so it is a complete mp3 frame. + * + * 'mp3buf' should be at least 7200 bytes long + * to hold all possible emitted data. + * + * After a call to this routine, the outputed mp3 data is complete, but + * you may continue to encode new PCM samples and write future mp3 data + * to a different file. The two mp3 files will play back with no gaps + * if they are concatenated together. + * + * This routine will NOT write id3v1 tags into the bitstream. + * + * return code = number of bytes output to mp3buf. Can be 0 + */ +int CDECL lame_encode_flush_nogap( + lame_global_flags * gfp, /* global context handle */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int size); /* number of valid octets in this stream */ + +/* + * OPTIONAL: + * Normally, this is called by lame_init_params(). It writes id3v2 and + * Xing headers into the front of the bitstream, and sets frame counters + * and bitrate histogram data to 0. You can also call this after + * lame_encode_flush_nogap(). + */ +int CDECL lame_init_bitstream( + lame_global_flags * gfp); /* global context handle */ + + + +/* + * OPTIONAL: some simple statistics + * a bitrate histogram to visualize the distribution of used frame sizes + * a stereo mode histogram to visualize the distribution of used stereo + * modes, useful in joint-stereo mode only + * 0: LR left-right encoded + * 1: LR-I left-right and intensity encoded (currently not supported) + * 2: MS mid-side encoded + * 3: MS-I mid-side and intensity encoded (currently not supported) + * + * attention: don't call them after lame_encode_finish + * suggested: lame_encode_flush -> lame_*_hist -> lame_close + */ + +void CDECL lame_bitrate_hist( + const lame_global_flags * gfp, + int bitrate_count[14] ); +void CDECL lame_bitrate_kbps( + const lame_global_flags * gfp, + int bitrate_kbps [14] ); +void CDECL lame_stereo_mode_hist( + const lame_global_flags * gfp, + int stereo_mode_count[4] ); + +void CDECL lame_bitrate_stereo_mode_hist ( + const lame_global_flags * gfp, + int bitrate_stmode_count[14][4] ); + +void CDECL lame_block_type_hist ( + const lame_global_flags * gfp, + int btype_count[6] ); + +void CDECL lame_bitrate_block_type_hist ( + const lame_global_flags * gfp, + int bitrate_btype_count[14][6] ); + +#if (DEPRECATED_OR_OBSOLETE_CODE_REMOVED && 0) +#else +/* + * OPTIONAL: + * lame_mp3_tags_fid will rewrite a Xing VBR tag to the mp3 file with file + * pointer fid. These calls perform forward and backwards seeks, so make + * sure fid is a real file. Make sure lame_encode_flush has been called, + * and all mp3 data has been written to the file before calling this + * function. + * NOTE: + * if VBR tags are turned off by the user, or turned off by LAME because + * the output is not a regular file, this call does nothing + * NOTE: + * LAME wants to read from the file to skip an optional ID3v2 tag, so + * make sure you opened the file for writing and reading. + * NOTE: + * You can call lame_get_lametag_frame instead, if you want to insert + * the lametag yourself. +*/ +void CDECL lame_mp3_tags_fid(lame_global_flags *, FILE* fid); +#endif + +/* + * OPTIONAL: + * lame_get_lametag_frame copies the final LAME-tag into 'buffer'. + * The function returns the number of bytes copied into buffer, or + * the required buffer size, if the provided buffer is too small. + * Function failed, if the return value is larger than 'size'! + * Make sure lame_encode flush has been called before calling this function. + * NOTE: + * if VBR tags are turned off by the user, or turned off by LAME, + * this call does nothing and returns 0. + * NOTE: + * LAME inserted an empty frame in the beginning of mp3 audio data, + * which you have to replace by the final LAME-tag frame after encoding. + * In case there is no ID3v2 tag, usually this frame will be the very first + * data in your mp3 file. If you put some other leading data into your + * file, you'll have to do some bookkeeping about where to write this buffer. + */ +size_t CDECL lame_get_lametag_frame( + const lame_global_flags *, unsigned char* buffer, size_t size); + +/* + * REQUIRED: + * final call to free all remaining buffers + */ +int CDECL lame_close (lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* + * OBSOLETE: + * lame_encode_finish combines lame_encode_flush() and lame_close() in + * one call. However, once this call is made, the statistics routines + * will no longer work because the data will have been cleared, and + * lame_mp3_tags_fid() cannot be called to add data to the VBR header + */ +int CDECL lame_encode_finish( + lame_global_flags* gfp, + unsigned char* mp3buf, + int size ); +#endif + + + + + + +/********************************************************************* + * + * decoding + * + * a simple interface to mpglib, part of mpg123, is also included if + * libmp3lame is compiled with HAVE_MPGLIB + * + *********************************************************************/ + +struct hip_global_struct; +typedef struct hip_global_struct hip_global_flags; +typedef hip_global_flags *hip_t; + + +typedef struct { + int header_parsed; /* 1 if header was parsed and following data was + computed */ + int stereo; /* number of channels */ + int samplerate; /* sample rate */ + int bitrate; /* bitrate */ + int mode; /* mp3 frame type */ + int mode_ext; /* mp3 frame type */ + int framesize; /* number of samples per mp3 frame */ + + /* this data is only computed if mpglib detects a Xing VBR header */ + unsigned long nsamp; /* number of samples in mp3 file. */ + int totalframes; /* total number of frames in mp3 file */ + + /* this data is not currently computed by the mpglib routines */ + int framenum; /* frames decoded counter */ +} mp3data_struct; + +/* required call to initialize decoder */ +hip_t CDECL hip_decode_init(void); + +/* cleanup call to exit decoder */ +int CDECL hip_decode_exit(hip_t gfp); + +/* HIP reporting functions */ +void CDECL hip_set_errorf(hip_t gfp, lame_report_function f); +void CDECL hip_set_debugf(hip_t gfp, lame_report_function f); +void CDECL hip_set_msgf (hip_t gfp, lame_report_function f); + +/********************************************************************* + * input 1 mp3 frame, output (maybe) pcm data. + * + * nout = hip_decode(hip, mp3buf,len,pcm_l,pcm_r); + * + * input: + * len : number of bytes of mp3 data in mp3buf + * mp3buf[len] : mp3 data to be decoded + * + * output: + * nout: -1 : decoding error + * 0 : need more data before we can complete the decode + * >0 : returned 'nout' samples worth of data in pcm_l,pcm_r + * pcm_l[nout] : left channel data + * pcm_r[nout] : right channel data + * + *********************************************************************/ +int CDECL hip_decode( hip_t gfp + , unsigned char * mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + ); + +/* same as hip_decode, and also returns mp3 header data */ +int CDECL hip_decode_headers( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + , mp3data_struct* mp3data + ); + +/* same as hip_decode, but returns at most one frame */ +int CDECL hip_decode1( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + ); + +/* same as hip_decode1, but returns at most one frame and mp3 header data */ +int CDECL hip_decode1_headers( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + , mp3data_struct* mp3data + ); + +/* same as hip_decode1_headers, but also returns enc_delay and enc_padding + from VBR Info tag, (-1 if no info tag was found) */ +int CDECL hip_decode1_headersB( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + , mp3data_struct* mp3data + , int *enc_delay + , int *enc_padding + ); + + + +/* OBSOLETE: + * lame_decode... functions are there to keep old code working + * but it is strongly recommended to replace calls by hip_decode... + * function calls, see above. + */ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +int CDECL lame_decode_init(void); +int CDECL lame_decode( + unsigned char * mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode1_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1_headersB( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data, + int *enc_delay, + int *enc_padding ); +int CDECL lame_decode_exit(void); + +#endif /* obsolete lame_decode API calls */ + + +/********************************************************************* + * + * id3tag stuff + * + *********************************************************************/ + +/* + * id3tag.h -- Interface to write ID3 version 1 and 2 tags. + * + * Copyright (C) 2000 Don Melton. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +/* utility to obtain alphabetically sorted list of genre names with numbers */ +void CDECL id3tag_genre_list( + void (*handler)(int, const char *, void *), + void* cookie); + +void CDECL id3tag_init (lame_t gfp); + +/* force addition of version 2 tag */ +void CDECL id3tag_add_v2 (lame_t gfp); + +/* add only a version 1 tag */ +void CDECL id3tag_v1_only (lame_t gfp); + +/* add only a version 2 tag */ +void CDECL id3tag_v2_only (lame_t gfp); + +/* pad version 1 tag with spaces instead of nulls */ +void CDECL id3tag_space_v1 (lame_t gfp); + +/* pad version 2 tag with extra 128 bytes */ +void CDECL id3tag_pad_v2 (lame_t gfp); + +/* pad version 2 tag with extra n bytes */ +void CDECL id3tag_set_pad (lame_t gfp, size_t n); + +void CDECL id3tag_set_title(lame_t gfp, const char* title); +void CDECL id3tag_set_artist(lame_t gfp, const char* artist); +void CDECL id3tag_set_album(lame_t gfp, const char* album); +void CDECL id3tag_set_year(lame_t gfp, const char* year); +void CDECL id3tag_set_comment(lame_t gfp, const char* comment); + +/* return -1 result if track number is out of ID3v1 range + and ignored for ID3v1 */ +int CDECL id3tag_set_track(lame_t gfp, const char* track); + +/* return non-zero result if genre name or number is invalid + result 0: OK + result -1: genre number out of range + result -2: no valid ID3v1 genre name, mapped to ID3v1 'Other' + but taken as-is for ID3v2 genre tag */ +int CDECL id3tag_set_genre(lame_t gfp, const char* genre); + +/* return non-zero result if field name is invalid */ +int CDECL id3tag_set_fieldvalue(lame_t gfp, const char* fieldvalue); + +/* return non-zero result if image type is invalid */ +int CDECL id3tag_set_albumart(lame_t gfp, const char* image, size_t size); + +/* lame_get_id3v1_tag copies ID3v1 tag into buffer. + * Function returns number of bytes copied into buffer, or number + * of bytes rquired if buffer 'size' is too small. + * Function fails, if returned value is larger than 'size'. + * NOTE: + * This functions does nothing, if user/LAME disabled ID3v1 tag. + */ +size_t CDECL lame_get_id3v1_tag(lame_t gfp, unsigned char* buffer, size_t size); + +/* lame_get_id3v2_tag copies ID3v2 tag into buffer. + * Function returns number of bytes copied into buffer, or number + * of bytes rquired if buffer 'size' is too small. + * Function fails, if returned value is larger than 'size'. + * NOTE: + * This functions does nothing, if user/LAME disabled ID3v2 tag. + */ +size_t CDECL lame_get_id3v2_tag(lame_t gfp, unsigned char* buffer, size_t size); + +/* normaly lame_init_param writes ID3v2 tags into the audio stream + * Call lame_set_write_id3tag_automatic(gfp, 0) before lame_init_param + * to turn off this behaviour and get ID3v2 tag with above function + * write it yourself into your file. + */ +void CDECL lame_set_write_id3tag_automatic(lame_global_flags * gfp, int); +int CDECL lame_get_write_id3tag_automatic(lame_global_flags const* gfp); + +/* experimental */ +int CDECL id3tag_set_textinfo_latin1(lame_t gfp, char const *id, char const *text); + +/* experimental */ +int CDECL id3tag_set_comment_latin1(lame_t gfp, char const *lang, char const *desc, char const *text); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* experimental */ +int CDECL id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text); + +/* experimental */ +int CDECL id3tag_set_comment_ucs2(lame_t gfp, char const *lang, + unsigned short const *desc, unsigned short const *text); + +/* experimental */ +int CDECL id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue); +#endif + +/* experimental */ +int CDECL id3tag_set_fieldvalue_utf16(lame_t gfp, const unsigned short *fieldvalue); + +/* experimental */ +int CDECL id3tag_set_textinfo_utf16(lame_t gfp, char const *id, unsigned short const *text); + +/* experimental */ +int CDECL id3tag_set_comment_utf16(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text); + + +/*********************************************************************** +* +* list of valid bitrates [kbps] & sample frequencies [Hz]. +* first index: 0: MPEG-2 values (sample frequencies 16...24 kHz) +* 1: MPEG-1 values (sample frequencies 32...48 kHz) +* 2: MPEG-2.5 values (sample frequencies 8...12 kHz) +***********************************************************************/ + +extern const int bitrate_table [3][16]; +extern const int samplerate_table [3][ 4]; + +/* access functions for use in DLL, global vars are not exported */ +int CDECL lame_get_bitrate(int mpeg_version, int table_index); +int CDECL lame_get_samplerate(int mpeg_version, int table_index); + + +/* maximum size of albumart image (128KB), which affects LAME_MAXMP3BUFFER + as well since lame_encode_buffer() also returns ID3v2 tag data */ +#define LAME_MAXALBUMART (128 * 1024) + +/* maximum size of mp3buffer needed if you encode at most 1152 samples for + each call to lame_encode_buffer. see lame_encode_buffer() below + (LAME_MAXMP3BUFFER is now obsolete) */ +#define LAME_MAXMP3BUFFER (16384 + LAME_MAXALBUMART) + + +typedef enum { + LAME_OKAY = 0, + LAME_NOERROR = 0, + LAME_GENERICERROR = -1, + LAME_NOMEM = -10, + LAME_BADBITRATE = -11, + LAME_BADSAMPFREQ = -12, + LAME_INTERNALERROR = -13, + + FRONTEND_READERROR = -80, + FRONTEND_WRITEERROR = -81, + FRONTEND_FILETOOLARGE = -82 + +} lame_errorcodes_t; + +#if defined(__cplusplus) +} +#endif +#endif /* LAME_LAME_H */ + diff --git a/pkg/lame/clame/lame_global_flags.h b/pkg/lame/clame/lame_global_flags.h new file mode 100644 index 0000000..ad9e677 --- /dev/null +++ b/pkg/lame/clame/lame_global_flags.h @@ -0,0 +1,184 @@ +#ifndef LAME_GLOBAL_FLAGS_H +#define LAME_GLOBAL_FLAGS_H + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined +struct lame_internal_flags; +typedef struct lame_internal_flags lame_internal_flags; +#endif + + +typedef enum short_block_e { + short_block_not_set = -1, /* allow LAME to decide */ + short_block_allowed = 0, /* LAME may use them, even different block types for L/R */ + short_block_coupled, /* LAME may use them, but always same block types in L/R */ + short_block_dispensed, /* LAME will not use short blocks, long blocks only */ + short_block_forced /* LAME will not use long blocks, short blocks only */ +} short_block_t; + +/*********************************************************************** +* +* Control Parameters set by User. These parameters are here for +* backwards compatibility with the old, non-shared lib API. +* Please use the lame_set_variablename() functions below +* +* +***********************************************************************/ +struct lame_global_struct { + unsigned int class_id; + + /* input description */ + unsigned long num_samples; /* number of samples. default=2^32-1 */ + int num_channels; /* input number of channels. default=2 */ + int samplerate_in; /* input_samp_rate in Hz. default=44.1 kHz */ + int samplerate_out; /* output_samp_rate. + default: LAME picks best value + at least not used for MP3 decoding: + Remember 44.1 kHz MP3s and AC97 */ + float scale; /* scale input by this amount before encoding + at least not used for MP3 decoding */ + float scale_left; /* scale input of channel 0 (left) by this + amount before encoding */ + float scale_right; /* scale input of channel 1 (right) by this + amount before encoding */ + + /* general control params */ + int analysis; /* collect data for a MP3 frame analyzer? */ + int write_lame_tag; /* add Xing VBR tag? */ + int decode_only; /* use lame/mpglib to convert mp3 to wav */ + int quality; /* quality setting 0=best, 9=worst default=5 */ + MPEG_mode mode; /* see enum in lame.h + default = LAME picks best value */ + int force_ms; /* force M/S mode. requires mode=1 */ + int free_format; /* use free format? default=0 */ + int findReplayGain; /* find the RG value? default=0 */ + int decode_on_the_fly; /* decode on the fly? default=0 */ + int write_id3tag_automatic; /* 1 (default) writes ID3 tags, 0 not */ + + int nogap_total; + int nogap_current; + + int substep_shaping; + int noise_shaping; + int subblock_gain; /* 0 = no, 1 = yes */ + int use_best_huffman; /* 0 = no. 1=outside loop 2=inside loop(slow) */ + + /* + * set either brate>0 or compression_ratio>0, LAME will compute + * the value of the variable not set. + * Default is compression_ratio = 11.025 + */ + int brate; /* bitrate */ + float compression_ratio; /* sizeof(wav file)/sizeof(mp3 file) */ + + + /* frame params */ + int copyright; /* mark as copyright. default=0 */ + int original; /* mark as original. default=1 */ + int extension; /* the MP3 'private extension' bit. + Meaningless */ + int emphasis; /* Input PCM is emphased PCM (for + instance from one of the rarely + emphased CDs), it is STRONGLY not + recommended to use this, because + psycho does not take it into account, + and last but not least many decoders + don't care about these bits */ + int error_protection; /* use 2 bytes per frame for a CRC + checksum. default=0 */ + int strict_ISO; /* enforce ISO spec as much as possible */ + + int disable_reservoir; /* use bit reservoir? */ + + /* quantization/noise shaping */ + int quant_comp; + int quant_comp_short; + int experimentalY; + int experimentalZ; + int exp_nspsytune; + + int preset; + + /* VBR control */ + vbr_mode VBR; + float VBR_q_frac; /* Range [0,...,1[ */ + int VBR_q; /* Range [0,...,9] */ + int VBR_mean_bitrate_kbps; + int VBR_min_bitrate_kbps; + int VBR_max_bitrate_kbps; + int VBR_hard_min; /* strictly enforce VBR_min_bitrate + normaly, it will be violated for analog + silence */ + + + /* resampling and filtering */ + int lowpassfreq; /* freq in Hz. 0=lame choses. + -1=no filter */ + int highpassfreq; /* freq in Hz. 0=lame choses. + -1=no filter */ + int lowpasswidth; /* freq width of filter, in Hz + (default=15%) */ + int highpasswidth; /* freq width of filter, in Hz + (default=15%) */ + + + + /* + * psycho acoustics and other arguments which you should not change + * unless you know what you are doing + */ + float maskingadjust; + float maskingadjust_short; + int ATHonly; /* only use ATH */ + int ATHshort; /* only use ATH for short blocks */ + int noATH; /* disable ATH */ + int ATHtype; /* select ATH formula */ + float ATHcurve; /* change ATH formula 4 shape */ + float ATH_lower_db; /* lower ATH by this many db */ + int athaa_type; /* select ATH auto-adjust scheme */ + float athaa_sensitivity; /* dB, tune active region of auto-level */ + short_block_t short_blocks; + int useTemporal; /* use temporal masking effect */ + float interChRatio; + float msfix; /* Naoki's adjustment of Mid/Side maskings */ + + int tune; /* 0 off, 1 on */ + float tune_value_a; /* used to pass values for debugging and stuff */ + + float attackthre; /* attack threshold for L/R/M channel */ + float attackthre_s; /* attack threshold for S channel */ + + + struct { + void (*msgf) (const char *format, va_list ap); + void (*debugf) (const char *format, va_list ap); + void (*errorf) (const char *format, va_list ap); + } report; + + /************************************************************************/ + /* internal variables, do not set... */ + /* provided because they may be of use to calling application */ + /************************************************************************/ + + int lame_allocated_gfp; /* is this struct owned by calling + program or lame? */ + + + + /**************************************************************************/ + /* more internal variables are stored in this structure: */ + /**************************************************************************/ + lame_internal_flags *internal_flags; + + + struct { + int mmx; + int amd3dnow; + int sse; + + } asm_optimizations; +}; + +int is_lame_global_flags_valid(const lame_global_flags * gfp); + +#endif /* LAME_GLOBAL_FLAGS_H */ diff --git a/pkg/lame/clame/lame_intrin.h b/pkg/lame/clame/lame_intrin.h new file mode 100644 index 0000000..bc4c189 --- /dev/null +++ b/pkg/lame/clame/lame_intrin.h @@ -0,0 +1,33 @@ +/* + * lame_intrin.h include file + * + * Copyright (c) 2006 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef LAME_INTRIN_H +#define LAME_INTRIN_H + + +void +init_xrpow_core_sse(gr_info * const cod_info, FLOAT xrpow[576], int upper, FLOAT * sum); + +void +fht_SSE2(FLOAT* , int); + +#endif diff --git a/pkg/lame/clame/machine.h b/pkg/lame/clame/machine.h new file mode 100644 index 0000000..bf6fff2 --- /dev/null +++ b/pkg/lame/clame/machine.h @@ -0,0 +1,189 @@ +/* + * Machine dependent defines/includes for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_MACHINE_H +#define LAME_MACHINE_H + +#include "version.h" + +#include +#include + +#ifdef STDC_HEADERS +# include +# include +#else +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr(), *strrchr(); +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define memmove(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(__riscos__) && defined(FPA10) +# include "ymath.h" +#else +# include +#endif +#include + +#include + +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif + +#if defined(macintosh) +# include +# include +#else +# include +# include +#endif + +#ifdef HAVE_INTTYPES_H +# include +#else +# ifdef HAVE_STDINT_H +# include +# endif +#endif + +#ifdef WITH_DMALLOC +#include +#endif + +/* + * 3 different types of pow() functions: + * - table lookup + * - pow() + * - exp() on some machines this is claimed to be faster than pow() + */ + +#define POW20(x) (assert(0 <= (x+Q_MAX2) && x < Q_MAX), pow20[x+Q_MAX2]) +/*#define POW20(x) pow(2.0,((double)(x)-210)*.25) */ +/*#define POW20(x) exp( ((double)(x)-210)*(.25*LOG2) ) */ + +#define IPOW20(x) (assert(0 <= x && x < Q_MAX), ipow20[x]) +/*#define IPOW20(x) exp( -((double)(x)-210)*.1875*LOG2 ) */ +/*#define IPOW20(x) pow(2.0,-((double)(x)-210)*.1875) */ + +/* in case this is used without configure */ +#ifndef inline +# define inline +#endif + +#if defined(_MSC_VER) +# undef inline +# define inline _inline +#elif defined(__SASC) || defined(__GNUC__) || defined(__ICC) || defined(__ECC) +/* if __GNUC__ we always want to inline, not only if the user requests it */ +# undef inline +# define inline __inline +#endif + +#if defined(_MSC_VER) +# pragma warning( disable : 4244 ) +/*# pragma warning( disable : 4305 ) */ +#endif + +/* + * FLOAT for variables which require at least 32 bits + * FLOAT8 for variables which require at least 64 bits + * + * On some machines, 64 bit will be faster than 32 bit. Also, some math + * routines require 64 bit float, so setting FLOAT=float will result in a + * lot of conversions. + */ + +#if ( defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) ) +# define WIN32_LEAN_AND_MEAN +# include +# include +# define FLOAT_MAX FLT_MAX +#else +# ifndef FLOAT +typedef float FLOAT; +# ifdef FLT_MAX +# define FLOAT_MAX FLT_MAX +# else +# define FLOAT_MAX 1e37 /* approx */ +# endif +# endif +#endif + +#ifndef FLOAT8 +typedef double FLOAT8; +# ifdef DBL_MAX +# define FLOAT8_MAX DBL_MAX +# else +# define FLOAT8_MAX 1e99 /* approx */ +# endif +#else +# ifdef FLT_MAX +# define FLOAT8_MAX FLT_MAX +# else +# define FLOAT8_MAX 1e37 /* approx */ +# endif +#endif + +/* sample_t must be floating point, at least 32 bits */ +typedef FLOAT sample_t; + +#define dimension_of(array) (sizeof(array)/sizeof(array[0])) +#define beyond(array) (array+dimension_of(array)) +#define compiletime_assert(expression) enum{static_assert_##FILE##_##LINE = 1/((expression)?1:0)} +#define lame_calloc(TYPE, COUNT) ((TYPE*)calloc(COUNT, sizeof(TYPE))) +#define multiple_of(CHUNK, COUNT) (\ + ( (COUNT) < 1 || (CHUNK) < 1 || (COUNT) % (CHUNK) == 0 ) \ + ? (COUNT) \ + : ((COUNT) + (CHUNK) - (COUNT) % (CHUNK)) \ + ) + +#if 1 +#define EQ(a,b) (\ +(fabs(a) > fabs(b)) \ + ? (fabs((a)-(b)) <= (fabs(a) * 1e-6f)) \ + : (fabs((a)-(b)) <= (fabs(b) * 1e-6f))) +#else +#define EQ(a,b) (fabs((a)-(b))<1E-37) +#endif + +#define NEQ(a,b) (!EQ(a,b)) + +#ifdef _MSC_VER +# if _MSC_VER < 1400 +# define fabsf fabs +# define powf pow +# define log10f log10 +# endif +#endif + +#endif + +/* end of machine.h */ diff --git a/pkg/lame/clame/mpglib_interface.c b/pkg/lame/clame/mpglib_interface.c new file mode 100644 index 0000000..d0f0b1d --- /dev/null +++ b/pkg/lame/clame/mpglib_interface.c @@ -0,0 +1,477 @@ +/* -*- mode: C; mode: fold -*- */ +/* + * LAME MP3 encoding engine + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2003 Olcios + * Copyright (c) 2008 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: mpglib_interface.c,v 1.44 2012/02/18 13:09:00 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_MPGLIB +#define hip_global_struct mpstr_tag +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "interface.h" + +#include "util.h" + + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* + * OBSOLETE: + * - kept to let it link + * - forward declaration to silence compiler + */ +int CDECL lame_decode_init(void); +int CDECL lame_decode( + unsigned char * mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode1_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1_headersB( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data, + int *enc_delay, + int *enc_padding ); +int CDECL lame_decode_exit(void); +#endif + + +static MPSTR mp; + +int +lame_decode_exit(void) +{ + ExitMP3(&mp); + return 0; +} + + +int +lame_decode_init(void) +{ + (void) InitMP3(&mp); + return 0; +} + + + + +/* copy mono samples */ +#define COPY_MONO(DST_TYPE, SRC_TYPE) \ + DST_TYPE *pcm_l = (DST_TYPE *)pcm_l_raw; \ + SRC_TYPE const *p_samples = (SRC_TYPE const *)p; \ + for (i = 0; i < processed_samples; i++) \ + *pcm_l++ = (DST_TYPE)(*p_samples++); + +/* copy stereo samples */ +#define COPY_STEREO(DST_TYPE, SRC_TYPE) \ + DST_TYPE *pcm_l = (DST_TYPE *)pcm_l_raw, *pcm_r = (DST_TYPE *)pcm_r_raw; \ + SRC_TYPE const *p_samples = (SRC_TYPE const *)p; \ + for (i = 0; i < processed_samples; i++) { \ + *pcm_l++ = (DST_TYPE)(*p_samples++); \ + *pcm_r++ = (DST_TYPE)(*p_samples++); \ + } + + + +/* + * For lame_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. either 576 or 1152 depending on MP3 file. + */ + +static int +decode1_headersB_clipchoice(PMPSTR pmp, unsigned char *buffer, size_t len, + char pcm_l_raw[], char pcm_r_raw[], mp3data_struct * mp3data, + int *enc_delay, int *enc_padding, + char *p, size_t psize, int decoded_sample_size, + int (*decodeMP3_ptr) (PMPSTR, unsigned char *, int, char *, int, + int *)) +{ + static const int smpls[2][4] = { + /* Layer I II III */ + {0, 384, 1152, 1152}, /* MPEG-1 */ + {0, 384, 1152, 576} /* MPEG-2(.5) */ + }; + + int processed_bytes; + int processed_samples; /* processed samples per channel */ + int ret; + int i; + int const len_l = len < INT_MAX ? (int) len : INT_MAX; + int const psize_l = psize < INT_MAX ? (int) psize : INT_MAX; + + mp3data->header_parsed = 0; + ret = (*decodeMP3_ptr) (pmp, buffer, len_l, p, psize_l, &processed_bytes); + /* three cases: + * 1. headers parsed, but data not complete + * pmp->header_parsed==1 + * pmp->framesize=0 + * pmp->fsizeold=size of last frame, or 0 if this is first frame + * + * 2. headers, data parsed, but ancillary data not complete + * pmp->header_parsed==1 + * pmp->framesize=size of frame + * pmp->fsizeold=size of last frame, or 0 if this is first frame + * + * 3. frame fully decoded: + * pmp->header_parsed==0 + * pmp->framesize=0 + * pmp->fsizeold=size of frame (which is now the last frame) + * + */ + if (pmp->header_parsed || pmp->fsizeold > 0 || pmp->framesize > 0) { + mp3data->header_parsed = 1; + mp3data->stereo = pmp->fr.stereo; + mp3data->samplerate = freqs[pmp->fr.sampling_frequency]; + mp3data->mode = pmp->fr.mode; + mp3data->mode_ext = pmp->fr.mode_ext; + mp3data->framesize = smpls[pmp->fr.lsf][pmp->fr.lay]; + + /* free format, we need the entire frame before we can determine + * the bitrate. If we haven't gotten the entire frame, bitrate=0 */ + if (pmp->fsizeold > 0) /* works for free format and fixed, no overrun, temporal results are < 400.e6 */ + mp3data->bitrate = 8 * (4 + pmp->fsizeold) * mp3data->samplerate / + (1.e3 * mp3data->framesize) + 0.5; + else if (pmp->framesize > 0) + mp3data->bitrate = 8 * (4 + pmp->framesize) * mp3data->samplerate / + (1.e3 * mp3data->framesize) + 0.5; + else + mp3data->bitrate = tabsel_123[pmp->fr.lsf][pmp->fr.lay - 1][pmp->fr.bitrate_index]; + + + + if (pmp->num_frames > 0) { + /* Xing VBR header found and num_frames was set */ + mp3data->totalframes = pmp->num_frames; + mp3data->nsamp = mp3data->framesize * pmp->num_frames; + *enc_delay = pmp->enc_delay; + *enc_padding = pmp->enc_padding; + } + } + + switch (ret) { + case MP3_OK: + switch (pmp->fr.stereo) { + case 1: + processed_samples = processed_bytes / decoded_sample_size; + if (decoded_sample_size == sizeof(short)) { + COPY_MONO(short, short) + } + else { + COPY_MONO(sample_t, FLOAT) + } + break; + case 2: + processed_samples = (processed_bytes / decoded_sample_size) >> 1; + if (decoded_sample_size == sizeof(short)) { + COPY_STEREO(short, short) + } + else { + COPY_STEREO(sample_t, FLOAT) + } + break; + default: + processed_samples = -1; + assert(0); + break; + } + break; + + case MP3_NEED_MORE: + processed_samples = 0; + break; + + case MP3_ERR: + processed_samples = -1; + break; + + default: + processed_samples = -1; + assert(0); + break; + } + + /*fprintf(stderr,"ok, more, err: %i %i %i\n", MP3_OK, MP3_NEED_MORE, MP3_ERR ); */ + /*fprintf(stderr,"ret = %i out=%i\n", ret, processed_samples ); */ + return processed_samples; +} + + +#define OUTSIZE_CLIPPED (4096*sizeof(short)) + +int +lame_decode1_headersB(unsigned char *buffer, + int len, + short pcm_l[], short pcm_r[], mp3data_struct * mp3data, + int *enc_delay, int *enc_padding) +{ + static char out[OUTSIZE_CLIPPED]; + + return decode1_headersB_clipchoice(&mp, buffer, len, (char *) pcm_l, (char *) pcm_r, mp3data, + enc_delay, enc_padding, out, OUTSIZE_CLIPPED, + sizeof(short), decodeMP3); +} + + + + + +/* + * For lame_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. Will be at most one frame of + * MPEG data. + */ + +int +lame_decode1_headers(unsigned char *buffer, + int len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int enc_delay, enc_padding; + return lame_decode1_headersB(buffer, len, pcm_l, pcm_r, mp3data, &enc_delay, &enc_padding); +} + + +int +lame_decode1(unsigned char *buffer, int len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + + return lame_decode1_headers(buffer, len, pcm_l, pcm_r, &mp3data); +} + + +/* + * For lame_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. a multiple of 576 or 1152 depending on MP3 file. + */ + +int +lame_decode_headers(unsigned char *buffer, + int len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int ret; + int totsize = 0; /* number of decoded samples per channel */ + + for (;;) { + switch (ret = lame_decode1_headers(buffer, len, pcm_l + totsize, pcm_r + totsize, mp3data)) { + case -1: + return ret; + case 0: + return totsize; + default: + totsize += ret; + len = 0; /* future calls to decodeMP3 are just to flush buffers */ + break; + } + } +} + + +int +lame_decode(unsigned char *buffer, int len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + + return lame_decode_headers(buffer, len, pcm_l, pcm_r, &mp3data); +} + + + + +hip_t hip_decode_init(void) +{ + hip_t hip = lame_calloc(hip_global_flags, 1); + InitMP3(hip); + return hip; +} + + +int hip_decode_exit(hip_t hip) +{ + if (hip) { + ExitMP3(hip); + free(hip); + } + return 0; +} + + +/* we forbid input with more than 1152 samples per channel for output in the unclipped mode */ +#define OUTSIZE_UNCLIPPED (1152*2*sizeof(FLOAT)) + +int +hip_decode1_unclipped(hip_t hip, unsigned char *buffer, size_t len, sample_t pcm_l[], sample_t pcm_r[]) +{ + static char out[OUTSIZE_UNCLIPPED]; + mp3data_struct mp3data; + int enc_delay, enc_padding; + + if (hip) { + return decode1_headersB_clipchoice(hip, buffer, len, (char *) pcm_l, (char *) pcm_r, &mp3data, + &enc_delay, &enc_padding, out, OUTSIZE_UNCLIPPED, + sizeof(FLOAT), decodeMP3_unclipped); + } + return 0; +} + +/* + * For hip_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. Will be at most one frame of + * MPEG data. + */ + +int +hip_decode1_headers(hip_t hip, unsigned char *buffer, + size_t len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int enc_delay, enc_padding; + return hip_decode1_headersB(hip, buffer, len, pcm_l, pcm_r, mp3data, &enc_delay, &enc_padding); +} + + +int +hip_decode1(hip_t hip, unsigned char *buffer, size_t len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + return hip_decode1_headers(hip, buffer, len, pcm_l, pcm_r, &mp3data); +} + + +/* + * For hip_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. a multiple of 576 or 1152 depending on MP3 file. + */ + +int +hip_decode_headers(hip_t hip, unsigned char *buffer, + size_t len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int ret; + int totsize = 0; /* number of decoded samples per channel */ + + for (;;) { + switch (ret = hip_decode1_headers(hip, buffer, len, pcm_l + totsize, pcm_r + totsize, mp3data)) { + case -1: + return ret; + case 0: + return totsize; + default: + totsize += ret; + len = 0; /* future calls to decodeMP3 are just to flush buffers */ + break; + } + } +} + + +int +hip_decode(hip_t hip, unsigned char *buffer, size_t len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + return hip_decode_headers(hip, buffer, len, pcm_l, pcm_r, &mp3data); +} + + +int +hip_decode1_headersB(hip_t hip, unsigned char *buffer, + size_t len, + short pcm_l[], short pcm_r[], mp3data_struct * mp3data, + int *enc_delay, int *enc_padding) +{ + static char out[OUTSIZE_CLIPPED]; + if (hip) { + return decode1_headersB_clipchoice(hip, buffer, len, (char *) pcm_l, (char *) pcm_r, mp3data, + enc_delay, enc_padding, out, OUTSIZE_CLIPPED, + sizeof(short), decodeMP3); + } + return -1; +} + + +void hip_set_pinfo(hip_t hip, plotting_data* pinfo) +{ + if (hip) { + hip->pinfo = pinfo; + } +} + + + +void hip_set_errorf(hip_t hip, lame_report_function func) +{ + if (hip) { + hip->report_err = func; + } +} + +void hip_set_debugf(hip_t hip, lame_report_function func) +{ + if (hip) { + hip->report_dbg = func; + } +} + +void hip_set_msgf (hip_t hip, lame_report_function func) +{ + if (hip) { + hip->report_msg = func; + } +} + +#endif + +/* end of mpglib_interface.c */ diff --git a/pkg/lame/clame/newmdct.c b/pkg/lame/clame/newmdct.c new file mode 100644 index 0000000..596cac9 --- /dev/null +++ b/pkg/lame/clame/newmdct.c @@ -0,0 +1,1039 @@ +/* + * MP3 window subband -> subband filtering -> mdct routine + * + * Copyright (c) 1999-2000 Takehiro Tominaga + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Special Thanks to Patrick De Smet for your advices. + */ + +/* $Id: newmdct.c,v 1.39 2011/05/07 16:05:17 rbrito Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "newmdct.h" + + + +#ifndef USE_GOGO_SUBBAND +static const FLOAT enwindow[] = { + -4.77e-07 * 0.740951125354959 / 2.384e-06, 1.03951e-04 * 0.740951125354959 / 2.384e-06, + 9.53674e-04 * 0.740951125354959 / 2.384e-06, 2.841473e-03 * 0.740951125354959 / 2.384e-06, + 3.5758972e-02 * 0.740951125354959 / 2.384e-06, 3.401756e-03 * 0.740951125354959 / 2.384e-06, 9.83715e-04 * 0.740951125354959 / 2.384e-06, 9.9182e-05 * 0.740951125354959 / 2.384e-06, /* 15 */ + 1.2398e-05 * 0.740951125354959 / 2.384e-06, 1.91212e-04 * 0.740951125354959 / 2.384e-06, + 2.283096e-03 * 0.740951125354959 / 2.384e-06, 1.6994476e-02 * 0.740951125354959 / 2.384e-06, + -1.8756866e-02 * 0.740951125354959 / 2.384e-06, -2.630711e-03 * 0.740951125354959 / 2.384e-06, + -2.47478e-04 * 0.740951125354959 / 2.384e-06, -1.4782e-05 * 0.740951125354959 / 2.384e-06, + 9.063471690191471e-01, + 1.960342806591213e-01, + + + -4.77e-07 * 0.773010453362737 / 2.384e-06, 1.05858e-04 * 0.773010453362737 / 2.384e-06, + 9.30786e-04 * 0.773010453362737 / 2.384e-06, 2.521515e-03 * 0.773010453362737 / 2.384e-06, + 3.5694122e-02 * 0.773010453362737 / 2.384e-06, 3.643036e-03 * 0.773010453362737 / 2.384e-06, 9.91821e-04 * 0.773010453362737 / 2.384e-06, 9.6321e-05 * 0.773010453362737 / 2.384e-06, /* 14 */ + 1.1444e-05 * 0.773010453362737 / 2.384e-06, 1.65462e-04 * 0.773010453362737 / 2.384e-06, + 2.110004e-03 * 0.773010453362737 / 2.384e-06, 1.6112804e-02 * 0.773010453362737 / 2.384e-06, + -1.9634247e-02 * 0.773010453362737 / 2.384e-06, -2.803326e-03 * 0.773010453362737 / 2.384e-06, + -2.77042e-04 * 0.773010453362737 / 2.384e-06, -1.6689e-05 * 0.773010453362737 / 2.384e-06, + 8.206787908286602e-01, + 3.901806440322567e-01, + + + -4.77e-07 * 0.803207531480645 / 2.384e-06, 1.07288e-04 * 0.803207531480645 / 2.384e-06, + 9.02653e-04 * 0.803207531480645 / 2.384e-06, 2.174854e-03 * 0.803207531480645 / 2.384e-06, + 3.5586357e-02 * 0.803207531480645 / 2.384e-06, 3.858566e-03 * 0.803207531480645 / 2.384e-06, 9.95159e-04 * 0.803207531480645 / 2.384e-06, 9.3460e-05 * 0.803207531480645 / 2.384e-06, /* 13 */ + 1.0014e-05 * 0.803207531480645 / 2.384e-06, 1.40190e-04 * 0.803207531480645 / 2.384e-06, + 1.937389e-03 * 0.803207531480645 / 2.384e-06, 1.5233517e-02 * 0.803207531480645 / 2.384e-06, + -2.0506859e-02 * 0.803207531480645 / 2.384e-06, -2.974033e-03 * 0.803207531480645 / 2.384e-06, + -3.07560e-04 * 0.803207531480645 / 2.384e-06, -1.8120e-05 * 0.803207531480645 / 2.384e-06, + 7.416505462720353e-01, + 5.805693545089249e-01, + + + -4.77e-07 * 0.831469612302545 / 2.384e-06, 1.08242e-04 * 0.831469612302545 / 2.384e-06, + 8.68797e-04 * 0.831469612302545 / 2.384e-06, 1.800537e-03 * 0.831469612302545 / 2.384e-06, + 3.5435200e-02 * 0.831469612302545 / 2.384e-06, 4.049301e-03 * 0.831469612302545 / 2.384e-06, 9.94205e-04 * 0.831469612302545 / 2.384e-06, 9.0599e-05 * 0.831469612302545 / 2.384e-06, /* 12 */ + 9.060e-06 * 0.831469612302545 / 2.384e-06, 1.16348e-04 * 0.831469612302545 / 2.384e-06, + 1.766682e-03 * 0.831469612302545 / 2.384e-06, 1.4358521e-02 * 0.831469612302545 / 2.384e-06, + -2.1372318e-02 * 0.831469612302545 / 2.384e-06, -3.14188e-03 * 0.831469612302545 / 2.384e-06, + -3.39031e-04 * 0.831469612302545 / 2.384e-06, -1.9550e-05 * 0.831469612302545 / 2.384e-06, + 6.681786379192989e-01, + 7.653668647301797e-01, + + + -4.77e-07 * 0.857728610000272 / 2.384e-06, 1.08719e-04 * 0.857728610000272 / 2.384e-06, + 8.29220e-04 * 0.857728610000272 / 2.384e-06, 1.399517e-03 * 0.857728610000272 / 2.384e-06, + 3.5242081e-02 * 0.857728610000272 / 2.384e-06, 4.215240e-03 * 0.857728610000272 / 2.384e-06, 9.89437e-04 * 0.857728610000272 / 2.384e-06, 8.7261e-05 * 0.857728610000272 / 2.384e-06, /* 11 */ + 8.106e-06 * 0.857728610000272 / 2.384e-06, 9.3937e-05 * 0.857728610000272 / 2.384e-06, + 1.597881e-03 * 0.857728610000272 / 2.384e-06, 1.3489246e-02 * 0.857728610000272 / 2.384e-06, + -2.2228718e-02 * 0.857728610000272 / 2.384e-06, -3.306866e-03 * 0.857728610000272 / 2.384e-06, + -3.71456e-04 * 0.857728610000272 / 2.384e-06, -2.1458e-05 * 0.857728610000272 / 2.384e-06, + 5.993769336819237e-01, + 9.427934736519954e-01, + + + -4.77e-07 * 0.881921264348355 / 2.384e-06, 1.08719e-04 * 0.881921264348355 / 2.384e-06, + 7.8392e-04 * 0.881921264348355 / 2.384e-06, 9.71317e-04 * 0.881921264348355 / 2.384e-06, + 3.5007000e-02 * 0.881921264348355 / 2.384e-06, 4.357815e-03 * 0.881921264348355 / 2.384e-06, 9.80854e-04 * 0.881921264348355 / 2.384e-06, 8.3923e-05 * 0.881921264348355 / 2.384e-06, /* 10 */ + 7.629e-06 * 0.881921264348355 / 2.384e-06, 7.2956e-05 * 0.881921264348355 / 2.384e-06, + 1.432419e-03 * 0.881921264348355 / 2.384e-06, 1.2627602e-02 * 0.881921264348355 / 2.384e-06, + -2.3074150e-02 * 0.881921264348355 / 2.384e-06, -3.467083e-03 * 0.881921264348355 / 2.384e-06, + -4.04358e-04 * 0.881921264348355 / 2.384e-06, -2.3365e-05 * 0.881921264348355 / 2.384e-06, + 5.345111359507916e-01, + 1.111140466039205e+00, + + + -9.54e-07 * 0.903989293123443 / 2.384e-06, 1.08242e-04 * 0.903989293123443 / 2.384e-06, + 7.31945e-04 * 0.903989293123443 / 2.384e-06, 5.15938e-04 * 0.903989293123443 / 2.384e-06, + 3.4730434e-02 * 0.903989293123443 / 2.384e-06, 4.477024e-03 * 0.903989293123443 / 2.384e-06, 9.68933e-04 * 0.903989293123443 / 2.384e-06, 8.0585e-05 * 0.903989293123443 / 2.384e-06, /* 9 */ + 6.676e-06 * 0.903989293123443 / 2.384e-06, 5.2929e-05 * 0.903989293123443 / 2.384e-06, + 1.269817e-03 * 0.903989293123443 / 2.384e-06, 1.1775017e-02 * 0.903989293123443 / 2.384e-06, + -2.3907185e-02 * 0.903989293123443 / 2.384e-06, -3.622532e-03 * 0.903989293123443 / 2.384e-06, + -4.38213e-04 * 0.903989293123443 / 2.384e-06, -2.5272e-05 * 0.903989293123443 / 2.384e-06, + 4.729647758913199e-01, + 1.268786568327291e+00, + + + -9.54e-07 * 0.92387953251128675613 / 2.384e-06, + 1.06812e-04 * 0.92387953251128675613 / 2.384e-06, + 6.74248e-04 * 0.92387953251128675613 / 2.384e-06, + 3.3379e-05 * 0.92387953251128675613 / 2.384e-06, + 3.4412861e-02 * 0.92387953251128675613 / 2.384e-06, + 4.573822e-03 * 0.92387953251128675613 / 2.384e-06, + 9.54151e-04 * 0.92387953251128675613 / 2.384e-06, + 7.6771e-05 * 0.92387953251128675613 / 2.384e-06, + 6.199e-06 * 0.92387953251128675613 / 2.384e-06, 3.4332e-05 * 0.92387953251128675613 / 2.384e-06, + 1.111031e-03 * 0.92387953251128675613 / 2.384e-06, + 1.0933399e-02 * 0.92387953251128675613 / 2.384e-06, + -2.4725437e-02 * 0.92387953251128675613 / 2.384e-06, + -3.771782e-03 * 0.92387953251128675613 / 2.384e-06, + -4.72546e-04 * 0.92387953251128675613 / 2.384e-06, + -2.7657e-05 * 0.92387953251128675613 / 2.384e-06, + 4.1421356237309504879e-01, /* tan(PI/8) */ + 1.414213562373095e+00, + + + -9.54e-07 * 0.941544065183021 / 2.384e-06, 1.05381e-04 * 0.941544065183021 / 2.384e-06, + 6.10352e-04 * 0.941544065183021 / 2.384e-06, -4.75883e-04 * 0.941544065183021 / 2.384e-06, + 3.4055710e-02 * 0.941544065183021 / 2.384e-06, 4.649162e-03 * 0.941544065183021 / 2.384e-06, 9.35555e-04 * 0.941544065183021 / 2.384e-06, 7.3433e-05 * 0.941544065183021 / 2.384e-06, /* 7 */ + 5.245e-06 * 0.941544065183021 / 2.384e-06, 1.7166e-05 * 0.941544065183021 / 2.384e-06, + 9.56535e-04 * 0.941544065183021 / 2.384e-06, 1.0103703e-02 * 0.941544065183021 / 2.384e-06, + -2.5527000e-02 * 0.941544065183021 / 2.384e-06, -3.914356e-03 * 0.941544065183021 / 2.384e-06, + -5.07355e-04 * 0.941544065183021 / 2.384e-06, -3.0041e-05 * 0.941544065183021 / 2.384e-06, + 3.578057213145241e-01, + 1.546020906725474e+00, + + + -9.54e-07 * 0.956940335732209 / 2.384e-06, 1.02520e-04 * 0.956940335732209 / 2.384e-06, + 5.39303e-04 * 0.956940335732209 / 2.384e-06, -1.011848e-03 * 0.956940335732209 / 2.384e-06, + 3.3659935e-02 * 0.956940335732209 / 2.384e-06, 4.703045e-03 * 0.956940335732209 / 2.384e-06, 9.15051e-04 * 0.956940335732209 / 2.384e-06, 7.0095e-05 * 0.956940335732209 / 2.384e-06, /* 6 */ + 4.768e-06 * 0.956940335732209 / 2.384e-06, 9.54e-07 * 0.956940335732209 / 2.384e-06, + 8.06808e-04 * 0.956940335732209 / 2.384e-06, 9.287834e-03 * 0.956940335732209 / 2.384e-06, + -2.6310921e-02 * 0.956940335732209 / 2.384e-06, -4.048824e-03 * 0.956940335732209 / 2.384e-06, + -5.42164e-04 * 0.956940335732209 / 2.384e-06, -3.2425e-05 * 0.956940335732209 / 2.384e-06, + 3.033466836073424e-01, + 1.662939224605090e+00, + + + -1.431e-06 * 0.970031253194544 / 2.384e-06, 9.9182e-05 * 0.970031253194544 / 2.384e-06, + 4.62532e-04 * 0.970031253194544 / 2.384e-06, -1.573563e-03 * 0.970031253194544 / 2.384e-06, + 3.3225536e-02 * 0.970031253194544 / 2.384e-06, 4.737377e-03 * 0.970031253194544 / 2.384e-06, 8.91685e-04 * 0.970031253194544 / 2.384e-06, 6.6280e-05 * 0.970031253194544 / 2.384e-06, /* 5 */ + 4.292e-06 * 0.970031253194544 / 2.384e-06, -1.3828e-05 * 0.970031253194544 / 2.384e-06, + 6.61850e-04 * 0.970031253194544 / 2.384e-06, 8.487225e-03 * 0.970031253194544 / 2.384e-06, + -2.7073860e-02 * 0.970031253194544 / 2.384e-06, -4.174709e-03 * 0.970031253194544 / 2.384e-06, + -5.76973e-04 * 0.970031253194544 / 2.384e-06, -3.4809e-05 * 0.970031253194544 / 2.384e-06, + 2.504869601913055e-01, + 1.763842528696710e+00, + + + -1.431e-06 * 0.98078528040323 / 2.384e-06, 9.5367e-05 * 0.98078528040323 / 2.384e-06, + 3.78609e-04 * 0.98078528040323 / 2.384e-06, -2.161503e-03 * 0.98078528040323 / 2.384e-06, + 3.2754898e-02 * 0.98078528040323 / 2.384e-06, 4.752159e-03 * 0.98078528040323 / 2.384e-06, 8.66413e-04 * 0.98078528040323 / 2.384e-06, 6.2943e-05 * 0.98078528040323 / 2.384e-06, /* 4 */ + 3.815e-06 * 0.98078528040323 / 2.384e-06, -2.718e-05 * 0.98078528040323 / 2.384e-06, + 5.22137e-04 * 0.98078528040323 / 2.384e-06, 7.703304e-03 * 0.98078528040323 / 2.384e-06, + -2.7815342e-02 * 0.98078528040323 / 2.384e-06, -4.290581e-03 * 0.98078528040323 / 2.384e-06, + -6.11782e-04 * 0.98078528040323 / 2.384e-06, -3.7670e-05 * 0.98078528040323 / 2.384e-06, + 1.989123673796580e-01, + 1.847759065022573e+00, + + + -1.907e-06 * 0.989176509964781 / 2.384e-06, 9.0122e-05 * 0.989176509964781 / 2.384e-06, + 2.88486e-04 * 0.989176509964781 / 2.384e-06, -2.774239e-03 * 0.989176509964781 / 2.384e-06, + 3.2248020e-02 * 0.989176509964781 / 2.384e-06, 4.748821e-03 * 0.989176509964781 / 2.384e-06, 8.38757e-04 * 0.989176509964781 / 2.384e-06, 5.9605e-05 * 0.989176509964781 / 2.384e-06, /* 3 */ + 3.338e-06 * 0.989176509964781 / 2.384e-06, -3.9577e-05 * 0.989176509964781 / 2.384e-06, + 3.88145e-04 * 0.989176509964781 / 2.384e-06, 6.937027e-03 * 0.989176509964781 / 2.384e-06, + -2.8532982e-02 * 0.989176509964781 / 2.384e-06, -4.395962e-03 * 0.989176509964781 / 2.384e-06, + -6.46591e-04 * 0.989176509964781 / 2.384e-06, -4.0531e-05 * 0.989176509964781 / 2.384e-06, + 1.483359875383474e-01, + 1.913880671464418e+00, + + + -1.907e-06 * 0.995184726672197 / 2.384e-06, 8.4400e-05 * 0.995184726672197 / 2.384e-06, + 1.91689e-04 * 0.995184726672197 / 2.384e-06, -3.411293e-03 * 0.995184726672197 / 2.384e-06, + 3.1706810e-02 * 0.995184726672197 / 2.384e-06, 4.728317e-03 * 0.995184726672197 / 2.384e-06, + 8.09669e-04 * 0.995184726672197 / 2.384e-06, 5.579e-05 * 0.995184726672197 / 2.384e-06, + 3.338e-06 * 0.995184726672197 / 2.384e-06, -5.0545e-05 * 0.995184726672197 / 2.384e-06, + 2.59876e-04 * 0.995184726672197 / 2.384e-06, 6.189346e-03 * 0.995184726672197 / 2.384e-06, + -2.9224873e-02 * 0.995184726672197 / 2.384e-06, -4.489899e-03 * 0.995184726672197 / 2.384e-06, + -6.80923e-04 * 0.995184726672197 / 2.384e-06, -4.3392e-05 * 0.995184726672197 / 2.384e-06, + 9.849140335716425e-02, + 1.961570560806461e+00, + + + -2.384e-06 * 0.998795456205172 / 2.384e-06, 7.7724e-05 * 0.998795456205172 / 2.384e-06, + 8.8215e-05 * 0.998795456205172 / 2.384e-06, -4.072189e-03 * 0.998795456205172 / 2.384e-06, + 3.1132698e-02 * 0.998795456205172 / 2.384e-06, 4.691124e-03 * 0.998795456205172 / 2.384e-06, + 7.79152e-04 * 0.998795456205172 / 2.384e-06, 5.2929e-05 * 0.998795456205172 / 2.384e-06, + 2.861e-06 * 0.998795456205172 / 2.384e-06, -6.0558e-05 * 0.998795456205172 / 2.384e-06, + 1.37329e-04 * 0.998795456205172 / 2.384e-06, 5.462170e-03 * 0.998795456205172 / 2.384e-06, + -2.9890060e-02 * 0.998795456205172 / 2.384e-06, -4.570484e-03 * 0.998795456205172 / 2.384e-06, + -7.14302e-04 * 0.998795456205172 / 2.384e-06, -4.6253e-05 * 0.998795456205172 / 2.384e-06, + 4.912684976946725e-02, + 1.990369453344394e+00, + + + 3.5780907e-02 * SQRT2 * 0.5 / 2.384e-06, 1.7876148e-02 * SQRT2 * 0.5 / 2.384e-06, + 3.134727e-03 * SQRT2 * 0.5 / 2.384e-06, 2.457142e-03 * SQRT2 * 0.5 / 2.384e-06, + 9.71317e-04 * SQRT2 * 0.5 / 2.384e-06, 2.18868e-04 * SQRT2 * 0.5 / 2.384e-06, + 1.01566e-04 * SQRT2 * 0.5 / 2.384e-06, 1.3828e-05 * SQRT2 * 0.5 / 2.384e-06, + + 3.0526638e-02 / 2.384e-06, 4.638195e-03 / 2.384e-06, 7.47204e-04 / 2.384e-06, + 4.9591e-05 / 2.384e-06, + 4.756451e-03 / 2.384e-06, 2.1458e-05 / 2.384e-06, -6.9618e-05 / 2.384e-06, /* 2.384e-06/2.384e-06 */ +}; +#endif + + +#define NS 12 +#define NL 36 + +static const FLOAT win[4][NL] = { + { + 2.382191739347913e-13, + 6.423305872147834e-13, + 9.400849094049688e-13, + 1.122435026096556e-12, + 1.183840321267481e-12, + 1.122435026096556e-12, + 9.400849094049690e-13, + 6.423305872147839e-13, + 2.382191739347918e-13, + + 5.456116108943412e-12, + 4.878985199565852e-12, + 4.240448995017367e-12, + 3.559909094758252e-12, + 2.858043359288075e-12, + 2.156177623817898e-12, + 1.475637723558783e-12, + 8.371015190102974e-13, + 2.599706096327376e-13, + + -5.456116108943412e-12, + -4.878985199565852e-12, + -4.240448995017367e-12, + -3.559909094758252e-12, + -2.858043359288076e-12, + -2.156177623817898e-12, + -1.475637723558783e-12, + -8.371015190102975e-13, + -2.599706096327376e-13, + + -2.382191739347923e-13, + -6.423305872147843e-13, + -9.400849094049696e-13, + -1.122435026096556e-12, + -1.183840321267481e-12, + -1.122435026096556e-12, + -9.400849094049694e-13, + -6.423305872147840e-13, + -2.382191739347918e-13, + }, + { + 2.382191739347913e-13, + 6.423305872147834e-13, + 9.400849094049688e-13, + 1.122435026096556e-12, + 1.183840321267481e-12, + 1.122435026096556e-12, + 9.400849094049688e-13, + 6.423305872147841e-13, + 2.382191739347918e-13, + + 5.456116108943413e-12, + 4.878985199565852e-12, + 4.240448995017367e-12, + 3.559909094758253e-12, + 2.858043359288075e-12, + 2.156177623817898e-12, + 1.475637723558782e-12, + 8.371015190102975e-13, + 2.599706096327376e-13, + + -5.461314069809755e-12, + -4.921085770524055e-12, + -4.343405037091838e-12, + -3.732668368707687e-12, + -3.093523840190885e-12, + -2.430835727329465e-12, + -1.734679010007751e-12, + -9.748253656609281e-13, + -2.797435120168326e-13, + + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + -2.283748241799531e-13, + -4.037858874020686e-13, + -2.146547464825323e-13, + }, + { + 1.316524975873958e-01, /* win[SHORT_TYPE] */ + 4.142135623730950e-01, + 7.673269879789602e-01, + + 1.091308501069271e+00, /* tantab_l */ + 1.303225372841206e+00, + 1.569685577117490e+00, + 1.920982126971166e+00, + 2.414213562373094e+00, + 3.171594802363212e+00, + 4.510708503662055e+00, + 7.595754112725146e+00, + 2.290376554843115e+01, + + 0.98480775301220802032, /* cx */ + 0.64278760968653936292, + 0.34202014332566882393, + 0.93969262078590842791, + -0.17364817766693030343, + -0.76604444311897790243, + 0.86602540378443870761, + 0.500000000000000e+00, + + -5.144957554275265e-01, /* ca */ + -4.717319685649723e-01, + -3.133774542039019e-01, + -1.819131996109812e-01, + -9.457419252642064e-02, + -4.096558288530405e-02, + -1.419856857247115e-02, + -3.699974673760037e-03, + + 8.574929257125442e-01, /* cs */ + 8.817419973177052e-01, + 9.496286491027329e-01, + 9.833145924917901e-01, + 9.955178160675857e-01, + 9.991605581781475e-01, + 9.998991952444470e-01, + 9.999931550702802e-01, + }, + { + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 2.283748241799531e-13, + 4.037858874020686e-13, + 2.146547464825323e-13, + + 5.461314069809755e-12, + 4.921085770524055e-12, + 4.343405037091838e-12, + 3.732668368707687e-12, + 3.093523840190885e-12, + 2.430835727329466e-12, + 1.734679010007751e-12, + 9.748253656609281e-13, + 2.797435120168326e-13, + + -5.456116108943413e-12, + -4.878985199565852e-12, + -4.240448995017367e-12, + -3.559909094758253e-12, + -2.858043359288075e-12, + -2.156177623817898e-12, + -1.475637723558782e-12, + -8.371015190102975e-13, + -2.599706096327376e-13, + + -2.382191739347913e-13, + -6.423305872147834e-13, + -9.400849094049688e-13, + -1.122435026096556e-12, + -1.183840321267481e-12, + -1.122435026096556e-12, + -9.400849094049688e-13, + -6.423305872147841e-13, + -2.382191739347918e-13, + } +}; + +#define tantab_l (win[SHORT_TYPE]+3) +#define cx (win[SHORT_TYPE]+12) +#define ca (win[SHORT_TYPE]+20) +#define cs (win[SHORT_TYPE]+28) + +/************************************************************************ +* +* window_subband() +* +* PURPOSE: Overlapping window on PCM samples +* +* SEMANTICS: +* 32 16-bit pcm samples are scaled to fractional 2's complement and +* concatenated to the end of the window buffer #x#. The updated window +* buffer #x# is then windowed by the analysis window #c# to produce the +* windowed sample #z# +* +************************************************************************/ + +/* + * new IDCT routine written by Takehiro TOMINAGA + */ +static const int order[] = { + 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, + 2, 3, 18, 19, 10, 11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 +}; + + +/* returns sum_j=0^31 a[j]*cos(PI*j*(k+1/2)/32), 0<=k<32 */ +inline static void +window_subband(const sample_t * x1, FLOAT a[SBLIMIT]) +{ + int i; + FLOAT const *wp = enwindow + 10; + + const sample_t *x2 = &x1[238 - 14 - 286]; + + for (i = -15; i < 0; i++) { + FLOAT w, s, t; + + w = wp[-10]; + s = x2[-224] * w; + t = x1[224] * w; + w = wp[-9]; + s += x2[-160] * w; + t += x1[160] * w; + w = wp[-8]; + s += x2[-96] * w; + t += x1[96] * w; + w = wp[-7]; + s += x2[-32] * w; + t += x1[32] * w; + w = wp[-6]; + s += x2[32] * w; + t += x1[-32] * w; + w = wp[-5]; + s += x2[96] * w; + t += x1[-96] * w; + w = wp[-4]; + s += x2[160] * w; + t += x1[-160] * w; + w = wp[-3]; + s += x2[224] * w; + t += x1[-224] * w; + + w = wp[-2]; + s += x1[-256] * w; + t -= x2[256] * w; + w = wp[-1]; + s += x1[-192] * w; + t -= x2[192] * w; + w = wp[0]; + s += x1[-128] * w; + t -= x2[128] * w; + w = wp[1]; + s += x1[-64] * w; + t -= x2[64] * w; + w = wp[2]; + s += x1[0] * w; + t -= x2[0] * w; + w = wp[3]; + s += x1[64] * w; + t -= x2[-64] * w; + w = wp[4]; + s += x1[128] * w; + t -= x2[-128] * w; + w = wp[5]; + s += x1[192] * w; + t -= x2[-192] * w; + + /* + * this multiplyer could be removed, but it needs more 256 FLOAT data. + * thinking about the data cache performance, I think we should not + * use such a huge table. tt 2000/Oct/25 + */ + s *= wp[6]; + w = t - s; + a[30 + i * 2] = t + s; + a[31 + i * 2] = wp[7] * w; + wp += 18; + x1--; + x2++; + } + { + FLOAT s, t, u, v; + t = x1[-16] * wp[-10]; + s = x1[-32] * wp[-2]; + t += (x1[-48] - x1[16]) * wp[-9]; + s += x1[-96] * wp[-1]; + t += (x1[-80] + x1[48]) * wp[-8]; + s += x1[-160] * wp[0]; + t += (x1[-112] - x1[80]) * wp[-7]; + s += x1[-224] * wp[1]; + t += (x1[-144] + x1[112]) * wp[-6]; + s -= x1[32] * wp[2]; + t += (x1[-176] - x1[144]) * wp[-5]; + s -= x1[96] * wp[3]; + t += (x1[-208] + x1[176]) * wp[-4]; + s -= x1[160] * wp[4]; + t += (x1[-240] - x1[208]) * wp[-3]; + s -= x1[224]; + + u = s - t; + v = s + t; + + t = a[14]; + s = a[15] - t; + + a[31] = v + t; /* A0 */ + a[30] = u + s; /* A1 */ + a[15] = u - s; /* A2 */ + a[14] = v - t; /* A3 */ + } + { + FLOAT xr; + xr = a[28] - a[0]; + a[0] += a[28]; + a[28] = xr * wp[-2 * 18 + 7]; + xr = a[29] - a[1]; + a[1] += a[29]; + a[29] = xr * wp[-2 * 18 + 7]; + + xr = a[26] - a[2]; + a[2] += a[26]; + a[26] = xr * wp[-4 * 18 + 7]; + xr = a[27] - a[3]; + a[3] += a[27]; + a[27] = xr * wp[-4 * 18 + 7]; + + xr = a[24] - a[4]; + a[4] += a[24]; + a[24] = xr * wp[-6 * 18 + 7]; + xr = a[25] - a[5]; + a[5] += a[25]; + a[25] = xr * wp[-6 * 18 + 7]; + + xr = a[22] - a[6]; + a[6] += a[22]; + a[22] = xr * SQRT2; + xr = a[23] - a[7]; + a[7] += a[23]; + a[23] = xr * SQRT2 - a[7]; + a[7] -= a[6]; + a[22] -= a[7]; + a[23] -= a[22]; + + xr = a[6]; + a[6] = a[31] - xr; + a[31] = a[31] + xr; + xr = a[7]; + a[7] = a[30] - xr; + a[30] = a[30] + xr; + xr = a[22]; + a[22] = a[15] - xr; + a[15] = a[15] + xr; + xr = a[23]; + a[23] = a[14] - xr; + a[14] = a[14] + xr; + + xr = a[20] - a[8]; + a[8] += a[20]; + a[20] = xr * wp[-10 * 18 + 7]; + xr = a[21] - a[9]; + a[9] += a[21]; + a[21] = xr * wp[-10 * 18 + 7]; + + xr = a[18] - a[10]; + a[10] += a[18]; + a[18] = xr * wp[-12 * 18 + 7]; + xr = a[19] - a[11]; + a[11] += a[19]; + a[19] = xr * wp[-12 * 18 + 7]; + + xr = a[16] - a[12]; + a[12] += a[16]; + a[16] = xr * wp[-14 * 18 + 7]; + xr = a[17] - a[13]; + a[13] += a[17]; + a[17] = xr * wp[-14 * 18 + 7]; + + xr = -a[20] + a[24]; + a[20] += a[24]; + a[24] = xr * wp[-12 * 18 + 7]; + xr = -a[21] + a[25]; + a[21] += a[25]; + a[25] = xr * wp[-12 * 18 + 7]; + + xr = a[4] - a[8]; + a[4] += a[8]; + a[8] = xr * wp[-12 * 18 + 7]; + xr = a[5] - a[9]; + a[5] += a[9]; + a[9] = xr * wp[-12 * 18 + 7]; + + xr = a[0] - a[12]; + a[0] += a[12]; + a[12] = xr * wp[-4 * 18 + 7]; + xr = a[1] - a[13]; + a[1] += a[13]; + a[13] = xr * wp[-4 * 18 + 7]; + xr = a[16] - a[28]; + a[16] += a[28]; + a[28] = xr * wp[-4 * 18 + 7]; + xr = -a[17] + a[29]; + a[17] += a[29]; + a[29] = xr * wp[-4 * 18 + 7]; + + xr = SQRT2 * (a[2] - a[10]); + a[2] += a[10]; + a[10] = xr; + xr = SQRT2 * (a[3] - a[11]); + a[3] += a[11]; + a[11] = xr; + xr = SQRT2 * (-a[18] + a[26]); + a[18] += a[26]; + a[26] = xr - a[18]; + xr = SQRT2 * (-a[19] + a[27]); + a[19] += a[27]; + a[27] = xr - a[19]; + + xr = a[2]; + a[19] -= a[3]; + a[3] -= xr; + a[2] = a[31] - xr; + a[31] += xr; + xr = a[3]; + a[11] -= a[19]; + a[18] -= xr; + a[3] = a[30] - xr; + a[30] += xr; + xr = a[18]; + a[27] -= a[11]; + a[19] -= xr; + a[18] = a[15] - xr; + a[15] += xr; + + xr = a[19]; + a[10] -= xr; + a[19] = a[14] - xr; + a[14] += xr; + xr = a[10]; + a[11] -= xr; + a[10] = a[23] - xr; + a[23] += xr; + xr = a[11]; + a[26] -= xr; + a[11] = a[22] - xr; + a[22] += xr; + xr = a[26]; + a[27] -= xr; + a[26] = a[7] - xr; + a[7] += xr; + + xr = a[27]; + a[27] = a[6] - xr; + a[6] += xr; + + xr = SQRT2 * (a[0] - a[4]); + a[0] += a[4]; + a[4] = xr; + xr = SQRT2 * (a[1] - a[5]); + a[1] += a[5]; + a[5] = xr; + xr = SQRT2 * (a[16] - a[20]); + a[16] += a[20]; + a[20] = xr; + xr = SQRT2 * (a[17] - a[21]); + a[17] += a[21]; + a[21] = xr; + + xr = -SQRT2 * (a[8] - a[12]); + a[8] += a[12]; + a[12] = xr - a[8]; + xr = -SQRT2 * (a[9] - a[13]); + a[9] += a[13]; + a[13] = xr - a[9]; + xr = -SQRT2 * (a[25] - a[29]); + a[25] += a[29]; + a[29] = xr - a[25]; + xr = -SQRT2 * (a[24] + a[28]); + a[24] -= a[28]; + a[28] = xr - a[24]; + + xr = a[24] - a[16]; + a[24] = xr; + xr = a[20] - xr; + a[20] = xr; + xr = a[28] - xr; + a[28] = xr; + + xr = a[25] - a[17]; + a[25] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[17] - a[1]; + a[17] = xr; + xr = a[9] - xr; + a[9] = xr; + xr = a[25] - xr; + a[25] = xr; + xr = a[5] - xr; + a[5] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[13] - xr; + a[13] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[1] - a[0]; + a[1] = xr; + xr = a[16] - xr; + a[16] = xr; + xr = a[17] - xr; + a[17] = xr; + xr = a[8] - xr; + a[8] = xr; + xr = a[9] - xr; + a[9] = xr; + xr = a[24] - xr; + a[24] = xr; + xr = a[25] - xr; + a[25] = xr; + xr = a[4] - xr; + a[4] = xr; + xr = a[5] - xr; + a[5] = xr; + xr = a[20] - xr; + a[20] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[12] - xr; + a[12] = xr; + xr = a[13] - xr; + a[13] = xr; + xr = a[28] - xr; + a[28] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[0]; + a[0] += a[31]; + a[31] -= xr; + xr = a[1]; + a[1] += a[30]; + a[30] -= xr; + xr = a[16]; + a[16] += a[15]; + a[15] -= xr; + xr = a[17]; + a[17] += a[14]; + a[14] -= xr; + xr = a[8]; + a[8] += a[23]; + a[23] -= xr; + xr = a[9]; + a[9] += a[22]; + a[22] -= xr; + xr = a[24]; + a[24] += a[7]; + a[7] -= xr; + xr = a[25]; + a[25] += a[6]; + a[6] -= xr; + xr = a[4]; + a[4] += a[27]; + a[27] -= xr; + xr = a[5]; + a[5] += a[26]; + a[26] -= xr; + xr = a[20]; + a[20] += a[11]; + a[11] -= xr; + xr = a[21]; + a[21] += a[10]; + a[10] -= xr; + xr = a[12]; + a[12] += a[19]; + a[19] -= xr; + xr = a[13]; + a[13] += a[18]; + a[18] -= xr; + xr = a[28]; + a[28] += a[3]; + a[3] -= xr; + xr = a[29]; + a[29] += a[2]; + a[2] -= xr; + } + +} + + +/*-------------------------------------------------------------------*/ +/* */ +/* Function: Calculation of the MDCT */ +/* In the case of long blocks (type 0,1,3) there are */ +/* 36 coefficents in the time domain and 18 in the frequency */ +/* domain. */ +/* In the case of short blocks (type 2) there are 3 */ +/* transformations with short length. This leads to 12 coefficents */ +/* in the time and 6 in the frequency domain. In this case the */ +/* results are stored side by side in the vector out[]. */ +/* */ +/* New layer3 */ +/* */ +/*-------------------------------------------------------------------*/ + +inline static void +mdct_short(FLOAT * inout) +{ + int l; + for (l = 0; l < 3; l++) { + FLOAT tc0, tc1, tc2, ts0, ts1, ts2; + + ts0 = inout[2 * 3] * win[SHORT_TYPE][0] - inout[5 * 3]; + tc0 = inout[0 * 3] * win[SHORT_TYPE][2] - inout[3 * 3]; + tc1 = ts0 + tc0; + tc2 = ts0 - tc0; + + ts0 = inout[5 * 3] * win[SHORT_TYPE][0] + inout[2 * 3]; + tc0 = inout[3 * 3] * win[SHORT_TYPE][2] + inout[0 * 3]; + ts1 = ts0 + tc0; + ts2 = -ts0 + tc0; + + tc0 = (inout[1 * 3] * win[SHORT_TYPE][1] - inout[4 * 3]) * 2.069978111953089e-11; /* tritab_s[1] */ + ts0 = (inout[4 * 3] * win[SHORT_TYPE][1] + inout[1 * 3]) * 2.069978111953089e-11; /* tritab_s[1] */ + + inout[3 * 0] = tc1 * 1.907525191737280e-11 /* tritab_s[2] */ + tc0; + inout[3 * 5] = -ts1 * 1.907525191737280e-11 /* tritab_s[0] */ + ts0; + + tc2 = tc2 * 0.86602540378443870761 * 1.907525191737281e-11 /* tritab_s[2] */ ; + ts1 = ts1 * 0.5 * 1.907525191737281e-11 + ts0; + inout[3 * 1] = tc2 - ts1; + inout[3 * 2] = tc2 + ts1; + + tc1 = tc1 * 0.5 * 1.907525191737281e-11 - tc0; + ts2 = ts2 * 0.86602540378443870761 * 1.907525191737281e-11 /* tritab_s[0] */ ; + inout[3 * 3] = tc1 + ts2; + inout[3 * 4] = tc1 - ts2; + + inout++; + } +} + +inline static void +mdct_long(FLOAT * out, FLOAT const *in) +{ + FLOAT ct, st; + { + FLOAT tc1, tc2, tc3, tc4, ts5, ts6, ts7, ts8; + /* 1,2, 5,6, 9,10, 13,14, 17 */ + tc1 = in[17] - in[9]; + tc3 = in[15] - in[11]; + tc4 = in[14] - in[12]; + ts5 = in[0] + in[8]; + ts6 = in[1] + in[7]; + ts7 = in[2] + in[6]; + ts8 = in[3] + in[5]; + + out[17] = (ts5 + ts7 - ts8) - (ts6 - in[4]); + st = (ts5 + ts7 - ts8) * cx[7] + (ts6 - in[4]); + ct = (tc1 - tc3 - tc4) * cx[6]; + out[5] = ct + st; + out[6] = ct - st; + + tc2 = (in[16] - in[10]) * cx[6]; + ts6 = ts6 * cx[7] + in[4]; + ct = tc1 * cx[0] + tc2 + tc3 * cx[1] + tc4 * cx[2]; + st = -ts5 * cx[4] + ts6 - ts7 * cx[5] + ts8 * cx[3]; + out[1] = ct + st; + out[2] = ct - st; + + ct = tc1 * cx[1] - tc2 - tc3 * cx[2] + tc4 * cx[0]; + st = -ts5 * cx[5] + ts6 - ts7 * cx[3] + ts8 * cx[4]; + out[9] = ct + st; + out[10] = ct - st; + + ct = tc1 * cx[2] - tc2 + tc3 * cx[0] - tc4 * cx[1]; + st = ts5 * cx[3] - ts6 + ts7 * cx[4] - ts8 * cx[5]; + out[13] = ct + st; + out[14] = ct - st; + } + { + FLOAT ts1, ts2, ts3, ts4, tc5, tc6, tc7, tc8; + + ts1 = in[8] - in[0]; + ts3 = in[6] - in[2]; + ts4 = in[5] - in[3]; + tc5 = in[17] + in[9]; + tc6 = in[16] + in[10]; + tc7 = in[15] + in[11]; + tc8 = in[14] + in[12]; + + out[0] = (tc5 + tc7 + tc8) + (tc6 + in[13]); + ct = (tc5 + tc7 + tc8) * cx[7] - (tc6 + in[13]); + st = (ts1 - ts3 + ts4) * cx[6]; + out[11] = ct + st; + out[12] = ct - st; + + ts2 = (in[7] - in[1]) * cx[6]; + tc6 = in[13] - tc6 * cx[7]; + ct = tc5 * cx[3] - tc6 + tc7 * cx[4] + tc8 * cx[5]; + st = ts1 * cx[2] + ts2 + ts3 * cx[0] + ts4 * cx[1]; + out[3] = ct + st; + out[4] = ct - st; + + ct = -tc5 * cx[5] + tc6 - tc7 * cx[3] - tc8 * cx[4]; + st = ts1 * cx[1] + ts2 - ts3 * cx[2] - ts4 * cx[0]; + out[7] = ct + st; + out[8] = ct - st; + + ct = -tc5 * cx[4] + tc6 - tc7 * cx[5] - tc8 * cx[3]; + st = ts1 * cx[0] - ts2 + ts3 * cx[1] - ts4 * cx[2]; + out[15] = ct + st; + out[16] = ct - st; + } +} + + +void +mdct_sub48(lame_internal_flags * gfc, const sample_t * w0, const sample_t * w1) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int gr, k, ch; + const sample_t *wk; + + wk = w0 + 286; + /* thinking cache performance, ch->gr loop is better than gr->ch loop */ + for (ch = 0; ch < cfg->channels_out; ch++) { + for (gr = 0; gr < cfg->mode_gr; gr++) { + int band; + gr_info *const gi = &(gfc->l3_side.tt[gr][ch]); + FLOAT *mdct_enc = gi->xr; + FLOAT *samp = esv->sb_sample[ch][1 - gr][0]; + + for (k = 0; k < 18 / 2; k++) { + window_subband(wk, samp); + window_subband(wk + 32, samp + 32); + samp += 64; + wk += 64; + /* + * Compensate for inversion in the analysis filter + */ + for (band = 1; band < 32; band += 2) { + samp[band - 32] *= -1; + } + } + + /* + * Perform imdct of 18 previous subband samples + * + 18 current subband samples + */ + for (band = 0; band < 32; band++, mdct_enc += 18) { + int type = gi->block_type; + FLOAT const *const band0 = esv->sb_sample[ch][gr][0] + order[band]; + FLOAT *const band1 = esv->sb_sample[ch][1 - gr][0] + order[band]; + if (gi->mixed_block_flag && band < 2) + type = 0; + if (esv->amp_filter[band] < 1e-12) { + memset(mdct_enc, 0, 18 * sizeof(FLOAT)); + } + else { + if (esv->amp_filter[band] < 1.0) { + for (k = 0; k < 18; k++) + band1[k * 32] *= esv->amp_filter[band]; + } + if (type == SHORT_TYPE) { + for (k = -NS / 4; k < 0; k++) { + FLOAT const w = win[SHORT_TYPE][k + 3]; + mdct_enc[k * 3 + 9] = band0[(9 + k) * 32] * w - band0[(8 - k) * 32]; + mdct_enc[k * 3 + 18] = band0[(14 - k) * 32] * w + band0[(15 + k) * 32]; + mdct_enc[k * 3 + 10] = band0[(15 + k) * 32] * w - band0[(14 - k) * 32]; + mdct_enc[k * 3 + 19] = band1[(2 - k) * 32] * w + band1[(3 + k) * 32]; + mdct_enc[k * 3 + 11] = band1[(3 + k) * 32] * w - band1[(2 - k) * 32]; + mdct_enc[k * 3 + 20] = band1[(8 - k) * 32] * w + band1[(9 + k) * 32]; + } + mdct_short(mdct_enc); + } + else { + FLOAT work[18]; + for (k = -NL / 4; k < 0; k++) { + FLOAT a, b; + a = win[type][k + 27] * band1[(k + 9) * 32] + + win[type][k + 36] * band1[(8 - k) * 32]; + b = win[type][k + 9] * band0[(k + 9) * 32] + - win[type][k + 18] * band0[(8 - k) * 32]; + work[k + 9] = a - b * tantab_l[k + 9]; + work[k + 18] = a * tantab_l[k + 9] + b; + } + + mdct_long(mdct_enc, work); + } + } + /* + * Perform aliasing reduction butterfly + */ + if (type != SHORT_TYPE && band != 0) { + for (k = 7; k >= 0; --k) { + FLOAT bu, bd; + bu = mdct_enc[k] * ca[k] + mdct_enc[-1 - k] * cs[k]; + bd = mdct_enc[k] * cs[k] - mdct_enc[-1 - k] * ca[k]; + + mdct_enc[-1 - k] = bu; + mdct_enc[k] = bd; + } + } + } + } + wk = w1 + 286; + if (cfg->mode_gr == 1) { + memcpy(esv->sb_sample[ch][0], esv->sb_sample[ch][1], 576 * sizeof(FLOAT)); + } + } +} diff --git a/pkg/lame/clame/newmdct.h b/pkg/lame/clame/newmdct.h new file mode 100644 index 0000000..0b58a95 --- /dev/null +++ b/pkg/lame/clame/newmdct.h @@ -0,0 +1,27 @@ +/* + * New Modified DCT include file + * + * Copyright (c) 1999 Takehiro TOMINAGA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_NEWMDCT_H +#define LAME_NEWMDCT_H + +void mdct_sub48(lame_internal_flags * gfc, const sample_t * w0, const sample_t * w1); + +#endif /* LAME_NEWMDCT_H */ diff --git a/pkg/lame/clame/presets.c b/pkg/lame/clame/presets.c new file mode 100644 index 0000000..93594f5 --- /dev/null +++ b/pkg/lame/clame/presets.c @@ -0,0 +1,404 @@ +/* + * presets.c -- Apply presets + * + * Copyright (c) 2002-2008 Gabriel Bouvigne + * Copyright (c) 2007-2012 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "set_get.h" +#include "encoder.h" +#include "util.h" +#include "lame_global_flags.h" + +#define SET_OPTION(opt, val, def) if (enforce) \ + (void) lame_set_##opt(gfp, val); \ + else if (!(fabs(lame_get_##opt(gfp) - def) > 0)) \ + (void) lame_set_##opt(gfp, val); + +#define SET__OPTION(opt, val, def) if (enforce) \ + lame_set_##opt(gfp, val); \ + else if (!(fabs(lame_get_##opt(gfp) - def) > 0)) \ + lame_set_##opt(gfp, val); + +#undef Min +#undef Max + +static inline int +min_int(int a, int b) +{ + if (a < b) { + return a; + } + return b; +} + +static inline int +max_int(int a, int b) +{ + if (a > b) { + return a; + } + return b; +} + + + +typedef struct { + int vbr_q; + int quant_comp; + int quant_comp_s; + int expY; + FLOAT st_lrm; /*short threshold */ + FLOAT st_s; + FLOAT masking_adj; + FLOAT masking_adj_short; + FLOAT ath_lower; + FLOAT ath_curve; + FLOAT ath_sensitivity; + FLOAT interch; + int safejoint; + int sfb21mod; + FLOAT msfix; + FLOAT minval; + FLOAT ath_fixpoint; +} vbr_presets_t; + + /* *INDENT-OFF* */ + + /* Switch mappings for VBR mode VBR_RH */ + static const vbr_presets_t vbr_old_switch_map[] = { + /*vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens interChR safejoint sfb21mod msfix */ + {0, 9, 9, 0, 5.20, 125.0, -4.2, -6.3, 4.8, 1, 0, 0, 2, 21, 0.97, 5, 100}, + {1, 9, 9, 0, 5.30, 125.0, -3.6, -5.6, 4.5, 1.5, 0, 0, 2, 21, 1.35, 5, 100}, + {2, 9, 9, 0, 5.60, 125.0, -2.2, -3.5, 2.8, 2, 0, 0, 2, 21, 1.49, 5, 100}, + {3, 9, 9, 1, 5.80, 130.0, -1.8, -2.8, 2.6, 3, -4, 0, 2, 20, 1.64, 5, 100}, + {4, 9, 9, 1, 6.00, 135.0, -0.7, -1.1, 1.1, 3.5, -8, 0, 2, 0, 1.79, 5, 100}, + {5, 9, 9, 1, 6.40, 140.0, 0.5, 0.4, -7.5, 4, -12, 0.0002, 0, 0, 1.95, 5, 100}, + {6, 9, 9, 1, 6.60, 145.0, 0.67, 0.65, -14.7, 6.5, -19, 0.0004, 0, 0, 2.30, 5, 100}, + {7, 9, 9, 1, 6.60, 145.0, 0.8, 0.75, -19.7, 8, -22, 0.0006, 0, 0, 2.70, 5, 100}, + {8, 9, 9, 1, 6.60, 145.0, 1.2, 1.15, -27.5, 10, -23, 0.0007, 0, 0, 0, 5, 100}, + {9, 9, 9, 1, 6.60, 145.0, 1.6, 1.6, -36, 11, -25, 0.0008, 0, 0, 0, 5, 100}, + {10, 9, 9, 1, 6.60, 145.0, 2.0, 2.0, -36, 12, -25, 0.0008, 0, 0, 0, 5, 100} + }; + + static const vbr_presets_t vbr_mt_psy_switch_map[] = { + /*vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens --- safejoint sfb21mod msfix */ + {0, 9, 9, 0, 4.20, 25.0, -6.8, -6.8, 7.1, 1, 0, 0, 2, 31, 1.000, 5, 100}, + {1, 9, 9, 0, 4.20, 25.0, -4.8, -4.8, 5.4, 1.4, -1, 0, 2, 27, 1.122, 5, 98}, + {2, 9, 9, 0, 4.20, 25.0, -2.6, -2.6, 3.7, 2.0, -3, 0, 2, 23, 1.288, 5, 97}, + {3, 9, 9, 1, 4.20, 25.0, -1.6, -1.6, 2.0, 2.0, -5, 0, 2, 18, 1.479, 5, 96}, + {4, 9, 9, 1, 4.20, 25.0, -0.0, -0.0, 0.0, 2.0, -8, 0, 2, 12, 1.698, 5, 95}, + {5, 9, 9, 1, 4.20, 25.0, 1.3, 1.3, -6, 3.5, -11, 0, 2, 8, 1.950, 5, 94.2}, +#if 0 + {6, 9, 9, 1, 4.50, 100.0, 1.5, 1.5, -24.0, 6.0, -14, 0, 2, 4, 2.239, 3, 93.9}, + {7, 9, 9, 1, 4.80, 200.0, 1.7, 1.7, -28.0, 9.0, -20, 0, 2, 0, 2.570, 1, 93.6}, +#else + {6, 9, 9, 1, 4.50, 100.0, 2.2, 2.3, -12.0, 6.0, -14, 0, 2, 4, 2.239, 3, 93.9}, + {7, 9, 9, 1, 4.80, 200.0, 2.7, 2.7, -18.0, 9.0, -17, 0, 2, 0, 2.570, 1, 93.6}, +#endif + {8, 9, 9, 1, 5.30, 300.0, 2.8, 2.8, -21.0, 10.0, -23, 0.0002, 0, 0, 2.951, 0, 93.3}, + {9, 9, 9, 1, 6.60, 300.0, 2.8, 2.8, -23.0, 11.0, -25, 0.0006, 0, 0, 3.388, 0, 93.3}, + {10, 9, 9, 1, 25.00, 300.0, 2.8, 2.8, -25.0, 12.0, -27, 0.0025, 0, 0, 3.500, 0, 93.3} + }; + + /* *INDENT-ON* */ + +static vbr_presets_t const* +get_vbr_preset(int v) +{ + switch (v) { + case vbr_mtrh: + case vbr_mt: + return &vbr_mt_psy_switch_map[0]; + default: + return &vbr_old_switch_map[0]; + } +} + +#define NOOP(m) (void)p.m +#define LERP(m) (p.m = p.m + x * (q.m - p.m)) + +static void +apply_vbr_preset(lame_global_flags * gfp, int a, int enforce) +{ + vbr_presets_t const *vbr_preset = get_vbr_preset(lame_get_VBR(gfp)); + float x = gfp->VBR_q_frac; + vbr_presets_t p = vbr_preset[a]; + vbr_presets_t q = vbr_preset[a + 1]; + vbr_presets_t const *set = &p; + + NOOP(vbr_q); + NOOP(quant_comp); + NOOP(quant_comp_s); + NOOP(expY); + LERP(st_lrm); + LERP(st_s); + LERP(masking_adj); + LERP(masking_adj_short); + LERP(ath_lower); + LERP(ath_curve); + LERP(ath_sensitivity); + LERP(interch); + NOOP(safejoint); + LERP(sfb21mod); + LERP(msfix); + LERP(minval); + LERP(ath_fixpoint); + + (void) lame_set_VBR_q(gfp, set->vbr_q); + SET_OPTION(quant_comp, set->quant_comp, -1); + SET_OPTION(quant_comp_short, set->quant_comp_s, -1); + if (set->expY) { + (void) lame_set_experimentalY(gfp, set->expY); + } + SET_OPTION(short_threshold_lrm, set->st_lrm, -1); + SET_OPTION(short_threshold_s, set->st_s, -1); + SET_OPTION(maskingadjust, set->masking_adj, 0); + SET_OPTION(maskingadjust_short, set->masking_adj_short, 0); + if (lame_get_VBR(gfp) == vbr_mt || lame_get_VBR(gfp) == vbr_mtrh) { + lame_set_ATHtype(gfp, 5); + } + SET_OPTION(ATHlower, set->ath_lower, 0); + SET_OPTION(ATHcurve, set->ath_curve, -1); + SET_OPTION(athaa_sensitivity, set->ath_sensitivity, 0); + if (set->interch > 0) { + SET_OPTION(interChRatio, set->interch, -1); + } + + /* parameters for which there is no proper set/get interface */ + if (set->safejoint > 0) { + (void) lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 2); + } + if (set->sfb21mod > 0) { + int const nsp = lame_get_exp_nspsytune(gfp); + int const val = (nsp >> 20) & 63; + if (val == 0) { + int const sf21mod = (set->sfb21mod << 20) | nsp; + (void) lame_set_exp_nspsytune(gfp, sf21mod); + } + } + SET__OPTION(msfix, set->msfix, -1); + + if (enforce == 0) { + gfp->VBR_q = a; + gfp->VBR_q_frac = x; + } + gfp->internal_flags->cfg.minval = set->minval; + { /* take care of gain adjustments */ + double const x = fabs(gfp->scale); + double const y = (x > 0.f) ? (10.f * log10(x)) : 0.f; + gfp->internal_flags->cfg.ATHfixpoint = set->ath_fixpoint - y; + } +} + +static int +apply_abr_preset(lame_global_flags * gfp, int preset, int enforce) +{ + typedef struct { + int abr_kbps; + int quant_comp; + int quant_comp_s; + int safejoint; + FLOAT nsmsfix; + FLOAT st_lrm; /*short threshold */ + FLOAT st_s; + FLOAT scale; + FLOAT masking_adj; + FLOAT ath_lower; + FLOAT ath_curve; + FLOAT interch; + int sfscale; + } abr_presets_t; + + + /* *INDENT-OFF* */ + + /* + * Switch mappings for ABR mode + */ + const abr_presets_t abr_switch_map[] = { + /* kbps quant q_s safejoint nsmsfix st_lrm st_s scale msk ath_lwr ath_curve interch , sfscale */ + { 8, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -30.0, 11, 0.0012, 1}, /* 8, impossible to use in stereo */ + { 16, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -25.0, 11, 0.0010, 1}, /* 16 */ + { 24, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -20.0, 11, 0.0010, 1}, /* 24 */ + { 32, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -15.0, 11, 0.0010, 1}, /* 32 */ + { 40, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -10.0, 11, 0.0009, 1}, /* 40 */ + { 48, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -10.0, 11, 0.0009, 1}, /* 48 */ + { 56, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -6.0, 11, 0.0008, 1}, /* 56 */ + { 64, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -2.0, 11, 0.0008, 1}, /* 64 */ + { 80, 9, 9, 0, 0, 6.60, 145, 0.95, 0, .0, 8, 0.0007, 1}, /* 80 */ + { 96, 9, 9, 0, 2.50, 6.60, 145, 0.95, 0, 1.0, 5.5, 0.0006, 1}, /* 96 */ + {112, 9, 9, 0, 2.25, 6.60, 145, 0.95, 0, 2.0, 4.5, 0.0005, 1}, /* 112 */ + {128, 9, 9, 0, 1.95, 6.40, 140, 0.95, 0, 3.0, 4, 0.0002, 1}, /* 128 */ + {160, 9, 9, 1, 1.79, 6.00, 135, 0.95, -2, 5.0, 3.5, 0, 1}, /* 160 */ + {192, 9, 9, 1, 1.49, 5.60, 125, 0.97, -4, 7.0, 3, 0, 0}, /* 192 */ + {224, 9, 9, 1, 1.25, 5.20, 125, 0.98, -6, 9.0, 2, 0, 0}, /* 224 */ + {256, 9, 9, 1, 0.97, 5.20, 125, 1.00, -8, 10.0, 1, 0, 0}, /* 256 */ + {320, 9, 9, 1, 0.90, 5.20, 125, 1.00, -10, 12.0, 0, 0, 0} /* 320 */ + }; + + /* *INDENT-ON* */ + + /* Variables for the ABR stuff */ + int r; + int actual_bitrate = preset; + + r = nearestBitrateFullIndex(preset); + + (void) lame_set_VBR(gfp, vbr_abr); + (void) lame_set_VBR_mean_bitrate_kbps(gfp, (actual_bitrate)); + (void) lame_set_VBR_mean_bitrate_kbps(gfp, min_int(lame_get_VBR_mean_bitrate_kbps(gfp), 320)); + (void) lame_set_VBR_mean_bitrate_kbps(gfp, max_int(lame_get_VBR_mean_bitrate_kbps(gfp), 8)); + (void) lame_set_brate(gfp, lame_get_VBR_mean_bitrate_kbps(gfp)); + + + /* parameters for which there is no proper set/get interface */ + if (abr_switch_map[r].safejoint > 0) + (void) lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 2); /* safejoint */ + + if (abr_switch_map[r].sfscale > 0) + (void) lame_set_sfscale(gfp, 1); + + + SET_OPTION(quant_comp, abr_switch_map[r].quant_comp, -1); + SET_OPTION(quant_comp_short, abr_switch_map[r].quant_comp_s, -1); + + SET__OPTION(msfix, abr_switch_map[r].nsmsfix, -1); + + SET_OPTION(short_threshold_lrm, abr_switch_map[r].st_lrm, -1); + SET_OPTION(short_threshold_s, abr_switch_map[r].st_s, -1); + + /* ABR seems to have big problems with clipping, especially at low bitrates */ + /* so we compensate for that here by using a scale value depending on bitrate */ + lame_set_scale(gfp, lame_get_scale(gfp) * abr_switch_map[r].scale); + + SET_OPTION(maskingadjust, abr_switch_map[r].masking_adj, 0); + if (abr_switch_map[r].masking_adj > 0) { + SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * .9, 0); + } + else { + SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * 1.1, 0); + } + + + SET_OPTION(ATHlower, abr_switch_map[r].ath_lower, 0); + SET_OPTION(ATHcurve, abr_switch_map[r].ath_curve, -1); + + SET_OPTION(interChRatio, abr_switch_map[r].interch, -1); + + (void) abr_switch_map[r].abr_kbps; + + gfp->internal_flags->cfg.minval = 5. * (abr_switch_map[r].abr_kbps / 320.); + + return preset; +} + + + +int +apply_preset(lame_global_flags * gfp, int preset, int enforce) +{ + /*translate legacy presets */ + switch (preset) { + case R3MIX: + { + preset = V3; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case MEDIUM: + case MEDIUM_FAST: + { + preset = V4; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case STANDARD: + case STANDARD_FAST: + { + preset = V2; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case EXTREME: + case EXTREME_FAST: + { + preset = V0; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case INSANE: + { + preset = 320; + gfp->preset = preset; + (void) apply_abr_preset(gfp, preset, enforce); + lame_set_VBR(gfp, vbr_off); + return preset; + } + } + + gfp->preset = preset; + { + switch (preset) { + case V9: + apply_vbr_preset(gfp, 9, enforce); + return preset; + case V8: + apply_vbr_preset(gfp, 8, enforce); + return preset; + case V7: + apply_vbr_preset(gfp, 7, enforce); + return preset; + case V6: + apply_vbr_preset(gfp, 6, enforce); + return preset; + case V5: + apply_vbr_preset(gfp, 5, enforce); + return preset; + case V4: + apply_vbr_preset(gfp, 4, enforce); + return preset; + case V3: + apply_vbr_preset(gfp, 3, enforce); + return preset; + case V2: + apply_vbr_preset(gfp, 2, enforce); + return preset; + case V1: + apply_vbr_preset(gfp, 1, enforce); + return preset; + case V0: + apply_vbr_preset(gfp, 0, enforce); + return preset; + default: + break; + } + } + if (8 <= preset && preset <= 320) { + return apply_abr_preset(gfp, preset, enforce); + } + + gfp->preset = 0; /*no corresponding preset found */ + return preset; +} diff --git a/pkg/lame/clame/psymodel.c b/pkg/lame/clame/psymodel.c new file mode 100644 index 0000000..60076ee --- /dev/null +++ b/pkg/lame/clame/psymodel.c @@ -0,0 +1,2167 @@ +/* + * psymodel.c + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2001-2002 Naoki Shibata + * Copyright (c) 2000-2003 Takehiro Tominaga + * Copyright (c) 2000-2012 Robert Hegemann + * Copyright (c) 2000-2005 Gabriel Bouvigne + * Copyright (c) 2000-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: psymodel.c,v 1.216 2017/09/06 19:38:23 aleidinger Exp $ */ + + +/* +PSYCHO ACOUSTICS + + +This routine computes the psycho acoustics, delayed by one granule. + +Input: buffer of PCM data (1024 samples). + +This window should be centered over the 576 sample granule window. +The routine will compute the psycho acoustics for +this granule, but return the psycho acoustics computed +for the *previous* granule. This is because the block +type of the previous granule can only be determined +after we have computed the psycho acoustics for the following +granule. + +Output: maskings and energies for each scalefactor band. +block type, PE, and some correlation measures. +The PE is used by CBR modes to determine if extra bits +from the bit reservoir should be used. The correlation +measures are used to determine mid/side or regular stereo. +*/ +/* +Notation: + +barks: a non-linear frequency scale. Mapping from frequency to + barks is given by freq2bark() + +scalefactor bands: The spectrum (frequencies) are broken into + SBMAX "scalefactor bands". Thes bands + are determined by the MPEG ISO spec. In + the noise shaping/quantization code, we allocate + bits among the partition bands to achieve the + best possible quality + +partition bands: The spectrum is also broken into about + 64 "partition bands". Each partition + band is about .34 barks wide. There are about 2-5 + partition bands for each scalefactor band. + +LAME computes all psycho acoustic information for each partition +band. Then at the end of the computations, this information +is mapped to scalefactor bands. The energy in each scalefactor +band is taken as the sum of the energy in all partition bands +which overlap the scalefactor band. The maskings can be computed +in the same way (and thus represent the average masking in that band) +or by taking the minmum value multiplied by the number of +partition bands used (which represents a minimum masking in that band). +*/ +/* +The general outline is as follows: + +1. compute the energy in each partition band +2. compute the tonality in each partition band +3. compute the strength of each partion band "masker" +4. compute the masking (via the spreading function applied to each masker) +5. Modifications for mid/side masking. + +Each partition band is considiered a "masker". The strength +of the i'th masker in band j is given by: + + s3(bark(i)-bark(j))*strength(i) + +The strength of the masker is a function of the energy and tonality. +The more tonal, the less masking. LAME uses a simple linear formula +(controlled by NMT and TMN) which says the strength is given by the +energy divided by a linear function of the tonality. +*/ +/* +s3() is the "spreading function". It is given by a formula +determined via listening tests. + +The total masking in the j'th partition band is the sum over +all maskings i. It is thus given by the convolution of +the strength with s3(), the "spreading function." + +masking(j) = sum_over_i s3(i-j)*strength(i) = s3 o strength + +where "o" = convolution operator. s3 is given by a formula determined +via listening tests. It is normalized so that s3 o 1 = 1. + +Note: instead of a simple convolution, LAME also has the +option of using "additive masking" + +The most critical part is step 2, computing the tonality of each +partition band. LAME has two tonality estimators. The first +is based on the ISO spec, and measures how predictiable the +signal is over time. The more predictable, the more tonal. +The second measure is based on looking at the spectrum of +a single granule. The more peaky the spectrum, the more +tonal. By most indications, the latter approach is better. + +Finally, in step 5, the maskings for the mid and side +channel are possibly increased. Under certain circumstances, +noise in the mid & side channels is assumed to also +be masked by strong maskers in the L or R channels. + + +Other data computed by the psy-model: + +ms_ratio side-channel / mid-channel masking ratio (for previous granule) +ms_ratio_next side-channel / mid-channel masking ratio for this granule + +percep_entropy[2] L and R values (prev granule) of PE - A measure of how + much pre-echo is in the previous granule +percep_entropy_MS[2] mid and side channel values (prev granule) of percep_entropy +energy[4] L,R,M,S energy in each channel, prev granule +blocktype_d[2] block type to use for previous granule +*/ + + + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "psymodel.h" +#include "lame_global_flags.h" +#include "fft.h" +#include "lame-analysis.h" + + +#define NSFIRLEN 21 + +#ifdef M_LN10 +#define LN_TO_LOG10 (M_LN10/10) +#else +#define LN_TO_LOG10 0.2302585093 +#endif + + +/* + L3psycho_anal. Compute psycho acoustics. + + Data returned to the calling program must be delayed by one + granule. + + This is done in two places. + If we do not need to know the blocktype, the copying + can be done here at the top of the program: we copy the data for + the last granule (computed during the last call) before it is + overwritten with the new data. It looks like this: + + 0. static psymodel_data + 1. calling_program_data = psymodel_data + 2. compute psymodel_data + + For data which needs to know the blocktype, the copying must be + done at the end of this loop, and the old values must be saved: + + 0. static psymodel_data_old + 1. compute psymodel_data + 2. compute possible block type of this granule + 3. compute final block type of previous granule based on #2. + 4. calling_program_data = psymodel_data_old + 5. psymodel_data_old = psymodel_data +*/ + + + + + +/* psycho_loudness_approx + jd - 2001 mar 12 +in: energy - BLKSIZE/2 elements of frequency magnitudes ^ 2 + gfp - uses out_samplerate, ATHtype (also needed for ATHformula) +returns: loudness^2 approximation, a positive value roughly tuned for a value + of 1.0 for signals near clipping. +notes: When calibrated, feeding this function binary white noise at sample + values +32767 or -32768 should return values that approach 3. + ATHformula is used to approximate an equal loudness curve. +future: Data indicates that the shape of the equal loudness curve varies + with intensity. This function might be improved by using an equal + loudness curve shaped for typical playback levels (instead of the + ATH, that is shaped for the threshold). A flexible realization might + simply bend the existing ATH curve to achieve the desired shape. + However, the potential gain may not be enough to justify an effort. +*/ +static FLOAT +psycho_loudness_approx(FLOAT const *energy, FLOAT const *eql_w) +{ + int i; + FLOAT loudness_power; + + loudness_power = 0.0; + /* apply weights to power in freq. bands */ + for (i = 0; i < BLKSIZE / 2; ++i) + loudness_power += energy[i] * eql_w[i]; + loudness_power *= VO_SCALE; + + return loudness_power; +} + +/* mask_add optimization */ +/* init the limit values used to avoid computing log in mask_add when it is not necessary */ + +/* For example, with i = 10*log10(m2/m1)/10*16 (= log10(m2/m1)*16) + * + * abs(i)>8 is equivalent (as i is an integer) to + * abs(i)>=9 + * i>=9 || i<=-9 + * equivalent to (as i is the biggest integer smaller than log10(m2/m1)*16 + * or the smallest integer bigger than log10(m2/m1)*16 depending on the sign of log10(m2/m1)*16) + * log10(m2/m1)>=9/16 || log10(m2/m1)<=-9/16 + * exp10 is strictly increasing thus this is equivalent to + * m2/m1 >= 10^(9/16) || m2/m1<=10^(-9/16) which are comparisons to constants + */ + + +#define I1LIMIT 8 /* as in if(i>8) */ +#define I2LIMIT 23 /* as in if(i>24) -> changed 23 */ +#define MLIMIT 15 /* as in if(m<15) */ + +/* pow(10, (I1LIMIT + 1) / 16.0); */ +static const FLOAT ma_max_i1 = 3.6517412725483771; +/* pow(10, (I2LIMIT + 1) / 16.0); */ +static const FLOAT ma_max_i2 = 31.622776601683793; +/* pow(10, (MLIMIT) / 10.0); */ +static const FLOAT ma_max_m = 31.622776601683793; + + /*This is the masking table: + According to tonality, values are going from 0dB (TMN) + to 9.3dB (NMT). + After additive masking computation, 8dB are added, so + final values are going from 8dB to 17.3dB + */ +static const FLOAT tab[] = { + 1.0 /*pow(10, -0) */ , + 0.79433 /*pow(10, -0.1) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.25119 /*pow(10, -0.6) */ , + 0.11749 /*pow(10, -0.93) */ +}; + +static const int tab_mask_add_delta[] = { 2, 2, 2, 1, 1, 1, 0, 0, -1 }; +#define STATIC_ASSERT_EQUAL_DIMENSION(A,B) enum{static_assert_##A=1/((dimension_of(A) == dimension_of(B))?1:0)} + +inline static int +mask_add_delta(int i) +{ + STATIC_ASSERT_EQUAL_DIMENSION(tab_mask_add_delta,tab); + assert(i < (int)dimension_of(tab)); + return tab_mask_add_delta[i]; +} + + +static void +init_mask_add_max_values(void) +{ +#ifndef NDEBUG + FLOAT const _ma_max_i1 = pow(10, (I1LIMIT + 1) / 16.0); + FLOAT const _ma_max_i2 = pow(10, (I2LIMIT + 1) / 16.0); + FLOAT const _ma_max_m = pow(10, (MLIMIT) / 10.0); + assert(fabs(ma_max_i1 - _ma_max_i1) <= FLT_EPSILON); + assert(fabs(ma_max_i2 - _ma_max_i2) <= FLT_EPSILON); + assert(fabs(ma_max_m - _ma_max_m ) <= FLT_EPSILON); +#endif +} + + + + +/* addition of simultaneous masking Naoki Shibata 2000/7 */ +inline static FLOAT +vbrpsy_mask_add(FLOAT m1, FLOAT m2, int b, int delta) +{ + static const FLOAT table2[] = { + 1.33352 * 1.33352, 1.35879 * 1.35879, 1.38454 * 1.38454, 1.39497 * 1.39497, + 1.40548 * 1.40548, 1.3537 * 1.3537, 1.30382 * 1.30382, 1.22321 * 1.22321, + 1.14758 * 1.14758, + 1 + }; + + FLOAT ratio; + + if (m1 < 0) { + m1 = 0; + } + if (m2 < 0) { + m2 = 0; + } + if (m1 <= 0) { + return m2; + } + if (m2 <= 0) { + return m1; + } + if (m2 > m1) { + ratio = m2 / m1; + } + else { + ratio = m1 / m2; + } + if (abs(b) <= delta) { /* approximately, 1 bark = 3 partitions */ + /* originally 'if(i > 8)' */ + if (ratio >= ma_max_i1) { + return m1 + m2; + } + else { + int i = (int) (FAST_LOG10_X(ratio, 16.0f)); + return (m1 + m2) * table2[i]; + } + } + if (ratio < ma_max_i2) { + return m1 + m2; + } + if (m1 < m2) { + m1 = m2; + } + return m1; +} + + +/* short block threshold calculation (part 2) + + partition band bo_s[sfb] is at the transition from scalefactor + band sfb to the next one sfb+1; enn and thmm have to be split + between them +*/ +static void +convert_partition2scalefac(PsyConst_CB2SB_t const *const gd, FLOAT const *eb, FLOAT const *thr, + FLOAT enn_out[], FLOAT thm_out[]) +{ + FLOAT enn, thmm; + int sb, b, n = gd->n_sb; + enn = thmm = 0.0f; + for (sb = b = 0; sb < n; ++b, ++sb) { + int const bo_sb = gd->bo[sb]; + int const npart = gd->npart; + int const b_lim = bo_sb < npart ? bo_sb : npart; + while (b < b_lim) { + assert(eb[b] >= 0); /* iff failed, it may indicate some index error elsewhere */ + assert(thr[b] >= 0); + enn += eb[b]; + thmm += thr[b]; + b++; + } + if (b >= npart) { + enn_out[sb] = enn; + thm_out[sb] = thmm; + ++sb; + break; + } + assert(eb[b] >= 0); /* iff failed, it may indicate some index error elsewhere */ + assert(thr[b] >= 0); + { + /* at transition sfb -> sfb+1 */ + FLOAT const w_curr = gd->bo_weight[sb]; + FLOAT const w_next = 1.0f - w_curr; + enn += w_curr * eb[b]; + thmm += w_curr * thr[b]; + enn_out[sb] = enn; + thm_out[sb] = thmm; + enn = w_next * eb[b]; + thmm = w_next * thr[b]; + } + } + /* zero initialize the rest */ + for (; sb < n; ++sb) { + enn_out[sb] = 0; + thm_out[sb] = 0; + } +} + +static void +convert_partition2scalefac_s(lame_internal_flags * gfc, FLOAT const *eb, FLOAT const *thr, int chn, + int sblock) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + FLOAT enn[SBMAX_s], thm[SBMAX_s]; + int sb; + convert_partition2scalefac(gds, eb, thr, enn, thm); + for (sb = 0; sb < SBMAX_s; ++sb) { + psv->en[chn].s[sb][sblock] = enn[sb]; + psv->thm[chn].s[sb][sblock] = thm[sb]; + } +} + +/* longblock threshold calculation (part 2) */ +static void +convert_partition2scalefac_l(lame_internal_flags * gfc, FLOAT const *eb, FLOAT const *thr, int chn) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + FLOAT *enn = &psv->en[chn].l[0]; + FLOAT *thm = &psv->thm[chn].l[0]; + convert_partition2scalefac(gdl, eb, thr, enn, thm); +} + +static void +convert_partition2scalefac_l_to_s(lame_internal_flags * gfc, FLOAT const *eb, FLOAT const *thr, + int chn) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->l_to_s; + FLOAT enn[SBMAX_s], thm[SBMAX_s]; + int sb, sblock; + convert_partition2scalefac(gds, eb, thr, enn, thm); + for (sb = 0; sb < SBMAX_s; ++sb) { + FLOAT const scale = 1. / 64.f; + FLOAT const tmp_enn = enn[sb]; + FLOAT const tmp_thm = thm[sb] * scale; + for (sblock = 0; sblock < 3; ++sblock) { + psv->en[chn].s[sb][sblock] = tmp_enn; + psv->thm[chn].s[sb][sblock] = tmp_thm; + } + } +} + + + +static inline FLOAT +NS_INTERP(FLOAT x, FLOAT y, FLOAT r) +{ + /* was pow((x),(r))*pow((y),1-(r)) */ + if (r >= 1.0f) + return x; /* 99.7% of the time */ + if (r <= 0.0f) + return y; + if (y > 0.0f) + return powf(x / y, r) * y; /* rest of the time */ + return 0.0f; /* never happens */ +} + + + +static FLOAT +pecalc_s(III_psy_ratio const *mr, FLOAT masking_lower) +{ + FLOAT pe_s; + static const FLOAT regcoef_s[] = { + 11.8, /* these values are tuned only for 44.1kHz... */ + 13.6, + 17.2, + 32, + 46.5, + 51.3, + 57.5, + 67.1, + 71.5, + 84.6, + 97.6, + 130, +/* 255.8 */ + }; + unsigned int sb, sblock; + + pe_s = 1236.28f / 4; + for (sb = 0; sb < SBMAX_s - 1; sb++) { + for (sblock = 0; sblock < 3; sblock++) { + FLOAT const thm = mr->thm.s[sb][sblock]; + assert(sb < dimension_of(regcoef_s)); + if (thm > 0.0f) { + FLOAT const x = thm * masking_lower; + FLOAT const en = mr->en.s[sb][sblock]; + if (en > x) { + if (en > x * 1e10f) { + pe_s += regcoef_s[sb] * (10.0f * LOG10); + } + else { + assert(x > 0); + pe_s += regcoef_s[sb] * FAST_LOG10(en / x); + } + } + } + } + } + + return pe_s; +} + +static FLOAT +pecalc_l(III_psy_ratio const *mr, FLOAT masking_lower) +{ + FLOAT pe_l; + static const FLOAT regcoef_l[] = { + 6.8, /* these values are tuned only for 44.1kHz... */ + 5.8, + 5.8, + 6.4, + 6.5, + 9.9, + 12.1, + 14.4, + 15, + 18.9, + 21.6, + 26.9, + 34.2, + 40.2, + 46.8, + 56.5, + 60.7, + 73.9, + 85.7, + 93.4, + 126.1, +/* 241.3 */ + }; + unsigned int sb; + + pe_l = 1124.23f / 4; + for (sb = 0; sb < SBMAX_l - 1; sb++) { + FLOAT const thm = mr->thm.l[sb]; + assert(sb < dimension_of(regcoef_l)); + if (thm > 0.0f) { + FLOAT const x = thm * masking_lower; + FLOAT const en = mr->en.l[sb]; + if (en > x) { + if (en > x * 1e10f) { + pe_l += regcoef_l[sb] * (10.0f * LOG10); + } + else { + assert(x > 0); + pe_l += regcoef_l[sb] * FAST_LOG10(en / x); + } + } + } + } + + return pe_l; +} + + +static void +calc_energy(PsyConst_CB2SB_t const *l, FLOAT const *fftenergy, FLOAT * eb, FLOAT * max, FLOAT * avg) +{ + int b, j; + + for (b = j = 0; b < l->npart; ++b) { + FLOAT ebb = 0, m = 0; + int i; + for (i = 0; i < l->numlines[b]; ++i, ++j) { + FLOAT const el = fftenergy[j]; + assert(el >= 0); + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + max[b] = m; + avg[b] = ebb * l->rnumlines[b]; + assert(l->rnumlines[b] >= 0); + assert(ebb >= 0); + assert(eb[b] >= 0); + assert(max[b] >= 0); + assert(avg[b] >= 0); + } +} + + +static void +calc_mask_index_l(lame_internal_flags const *gfc, FLOAT const *max, + FLOAT const *avg, unsigned char *mask_idx) +{ + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + FLOAT m, a; + int b, k; + int const last_tab_entry = sizeof(tab) / sizeof(tab[0]) - 1; + b = 0; + a = avg[b] + avg[b + 1]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gdl->numlines[b] + gdl->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gdl->numlines[b] + gdl->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + + for (b = 1; b < gdl->npart - 1; b++) { + a = avg[b - 1] + avg[b] + avg[b + 1]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gdl->numlines[b - 1] + gdl->numlines[b] + gdl->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 3.0f - a) + / (a * (gdl->numlines[b - 1] + gdl->numlines[b] + gdl->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + } + assert(b > 0); + assert(b == gdl->npart - 1); + + a = avg[b - 1] + avg[b]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + assert((gdl->numlines[b - 1] + gdl->numlines[b] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gdl->numlines[b - 1] + gdl->numlines[b] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + assert(b == (gdl->npart - 1)); +} + + +static void +vbrpsy_compute_fft_l(lame_internal_flags * gfc, const sample_t * const buffer[2], int chn, + int gr_out, FLOAT fftenergy[HBLKSIZE], FLOAT(*wsamp_l)[BLKSIZE]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + PsyStateVar_t *psv = &gfc->sv_psy; + plotting_data *plt = cfg->analysis ? gfc->pinfo : 0; + int j; + + if (chn < 2) { + fft_long(gfc, *wsamp_l, chn, buffer); + } + else if (chn == 2) { + FLOAT const sqrt2_half = SQRT2 * 0.5f; + /* FFT data for mid and side channel is derived from L & R */ + for (j = BLKSIZE - 1; j >= 0; --j) { + FLOAT const l = wsamp_l[0][j]; + FLOAT const r = wsamp_l[1][j]; + wsamp_l[0][j] = (l + r) * sqrt2_half; + wsamp_l[1][j] = (l - r) * sqrt2_half; + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy[0] = wsamp_l[0][0]; + fftenergy[0] *= fftenergy[0]; + + for (j = BLKSIZE / 2 - 1; j >= 0; --j) { + FLOAT const re = (*wsamp_l)[BLKSIZE / 2 - j]; + FLOAT const im = (*wsamp_l)[BLKSIZE / 2 + j]; + fftenergy[BLKSIZE / 2 - j] = (re * re + im * im) * 0.5f; + } + /* total energy */ + { + FLOAT totalenergy = 0.0f; + for (j = 11; j < HBLKSIZE; j++) + totalenergy += fftenergy[j]; + + psv->tot_ener[chn] = totalenergy; + } + + if (plt) { + for (j = 0; j < HBLKSIZE; j++) { + plt->energy[gr_out][chn][j] = plt->energy_save[chn][j]; + plt->energy_save[chn][j] = fftenergy[j]; + } + } +} + + +static void +vbrpsy_compute_fft_s(lame_internal_flags const *gfc, const sample_t * const buffer[2], int chn, + int sblock, FLOAT(*fftenergy_s)[HBLKSIZE_s], FLOAT(*wsamp_s)[3][BLKSIZE_s]) +{ + int j; + + if (sblock == 0 && chn < 2) { + fft_short(gfc, *wsamp_s, chn, buffer); + } + if (chn == 2) { + FLOAT const sqrt2_half = SQRT2 * 0.5f; + /* FFT data for mid and side channel is derived from L & R */ + for (j = BLKSIZE_s - 1; j >= 0; --j) { + FLOAT const l = wsamp_s[0][sblock][j]; + FLOAT const r = wsamp_s[1][sblock][j]; + wsamp_s[0][sblock][j] = (l + r) * sqrt2_half; + wsamp_s[1][sblock][j] = (l - r) * sqrt2_half; + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy_s[sblock][0] = (*wsamp_s)[sblock][0]; + fftenergy_s[sblock][0] *= fftenergy_s[sblock][0]; + for (j = BLKSIZE_s / 2 - 1; j >= 0; --j) { + FLOAT const re = (*wsamp_s)[sblock][BLKSIZE_s / 2 - j]; + FLOAT const im = (*wsamp_s)[sblock][BLKSIZE_s / 2 + j]; + fftenergy_s[sblock][BLKSIZE_s / 2 - j] = (re * re + im * im) * 0.5f; + } +} + + + /********************************************************************* + * compute loudness approximation (used for ATH auto-level adjustment) + *********************************************************************/ +static void +vbrpsy_compute_loudness_approximation_l(lame_internal_flags * gfc, int gr_out, int chn, + const FLOAT fftenergy[HBLKSIZE]) +{ + PsyStateVar_t *psv = &gfc->sv_psy; + if (chn < 2) { /*no loudness for mid/side ch */ + gfc->ov_psy.loudness_sq[gr_out][chn] = psv->loudness_sq_save[chn]; + psv->loudness_sq_save[chn] = psycho_loudness_approx(fftenergy, gfc->ATH->eql_w); + } +} + + + /********************************************************************** + * Apply HPF of fs/4 to the input signal. + * This is used for attack detection / handling. + **********************************************************************/ +static void +vbrpsy_attack_detection(lame_internal_flags * gfc, const sample_t * const buffer[2], int gr_out, + III_psy_ratio masking_ratio[2][2], III_psy_ratio masking_MS_ratio[2][2], + FLOAT energy[4], FLOAT sub_short_factor[4][3], int ns_attacks[4][4], + int uselongblock[2]) +{ + FLOAT ns_hpfsmpl[2][576]; + SessionConfig_t const *const cfg = &gfc->cfg; + PsyStateVar_t *const psv = &gfc->sv_psy; + plotting_data *plt = cfg->analysis ? gfc->pinfo : 0; + int const n_chn_out = cfg->channels_out; + /* chn=2 and 3 = Mid and Side channels */ + int const n_chn_psy = (cfg->mode == JOINT_STEREO) ? 4 : n_chn_out; + int chn, i, j; + + memset(&ns_hpfsmpl[0][0], 0, sizeof(ns_hpfsmpl)); + /* Don't copy the input buffer into a temporary buffer */ + /* unroll the loop 2 times */ + for (chn = 0; chn < n_chn_out; chn++) { + static const FLOAT fircoef[] = { + -8.65163e-18 * 2, -0.00851586 * 2, -6.74764e-18 * 2, 0.0209036 * 2, + -3.36639e-17 * 2, -0.0438162 * 2, -1.54175e-17 * 2, 0.0931738 * 2, + -5.52212e-17 * 2, -0.313819 * 2 + }; + /* apply high pass filter of fs/4 */ + const sample_t *const firbuf = &buffer[chn][576 - 350 - NSFIRLEN + 192]; + assert(dimension_of(fircoef) == ((NSFIRLEN - 1) / 2)); + for (i = 0; i < 576; i++) { + FLOAT sum1, sum2; + sum1 = firbuf[i + 10]; + sum2 = 0.0; + for (j = 0; j < ((NSFIRLEN - 1) / 2) - 1; j += 2) { + sum1 += fircoef[j] * (firbuf[i + j] + firbuf[i + NSFIRLEN - j]); + sum2 += fircoef[j + 1] * (firbuf[i + j + 1] + firbuf[i + NSFIRLEN - j - 1]); + } + ns_hpfsmpl[chn][i] = sum1 + sum2; + } + masking_ratio[gr_out][chn].en = psv->en[chn]; + masking_ratio[gr_out][chn].thm = psv->thm[chn]; + if (n_chn_psy > 2) { + /* MS maskings */ + /*percep_MS_entropy [chn-2] = gfc -> pe [chn]; */ + masking_MS_ratio[gr_out][chn].en = psv->en[chn + 2]; + masking_MS_ratio[gr_out][chn].thm = psv->thm[chn + 2]; + } + } + for (chn = 0; chn < n_chn_psy; chn++) { + FLOAT attack_intensity[12]; + FLOAT en_subshort[12]; + FLOAT en_short[4] = { 0, 0, 0, 0 }; + FLOAT const *pf = ns_hpfsmpl[chn & 1]; + int ns_uselongblock = 1; + + if (chn == 2) { + for (i = 0, j = 576; j > 0; ++i, --j) { + FLOAT const l = ns_hpfsmpl[0][i]; + FLOAT const r = ns_hpfsmpl[1][i]; + ns_hpfsmpl[0][i] = l + r; + ns_hpfsmpl[1][i] = l - r; + } + } + /*************************************************************** + * determine the block type (window type) + ***************************************************************/ + /* calculate energies of each sub-shortblocks */ + for (i = 0; i < 3; i++) { + en_subshort[i] = psv->last_en_subshort[chn][i + 6]; + assert(psv->last_en_subshort[chn][i + 4] > 0); + attack_intensity[i] = en_subshort[i] / psv->last_en_subshort[chn][i + 4]; + en_short[0] += en_subshort[i]; + } + + for (i = 0; i < 9; i++) { + FLOAT const *const pfe = pf + 576 / 9; + FLOAT p = 1.; + for (; pf < pfe; pf++) + if (p < fabs(*pf)) + p = fabs(*pf); + psv->last_en_subshort[chn][i] = en_subshort[i + 3] = p; + en_short[1 + i / 3] += p; + if (p > en_subshort[i + 3 - 2]) { + assert(en_subshort[i + 3 - 2] > 0); + p = p / en_subshort[i + 3 - 2]; + } + else if (en_subshort[i + 3 - 2] > p * 10.0f) { + assert(p > 0); + p = en_subshort[i + 3 - 2] / (p * 10.0f); + } + else { + p = 0.0; + } + attack_intensity[i + 3] = p; + } + + /* pulse like signal detection for fatboy.wav and so on */ + for (i = 0; i < 3; ++i) { + FLOAT const enn = + en_subshort[i * 3 + 3] + en_subshort[i * 3 + 4] + en_subshort[i * 3 + 5]; + FLOAT factor = 1.f; + if (en_subshort[i * 3 + 5] * 6 < enn) { + factor *= 0.5f; + if (en_subshort[i * 3 + 4] * 6 < enn) { + factor *= 0.5f; + } + } + sub_short_factor[chn][i] = factor; + } + + if (plt) { + FLOAT x = attack_intensity[0]; + for (i = 1; i < 12; i++) { + if (x < attack_intensity[i]) { + x = attack_intensity[i]; + } + } + plt->ers[gr_out][chn] = plt->ers_save[chn]; + plt->ers_save[chn] = x; + } + + /* compare energies between sub-shortblocks */ + { + FLOAT x = gfc->cd_psy->attack_threshold[chn]; + for (i = 0; i < 12; i++) { + if (ns_attacks[chn][i / 3] == 0) { + if (attack_intensity[i] > x) { + ns_attacks[chn][i / 3] = (i % 3) + 1; + } + } + } + } + /* should have energy change between short blocks, in order to avoid periodic signals */ + /* Good samples to show the effect are Trumpet test songs */ + /* GB: tuned (1) to avoid too many short blocks for test sample TRUMPET */ + /* RH: tuned (2) to let enough short blocks through for test sample FSOL and SNAPS */ + for (i = 1; i < 4; i++) { + FLOAT const u = en_short[i - 1]; + FLOAT const v = en_short[i]; + FLOAT const m = Max(u, v); + if (m < 40000) { /* (2) */ + if (u < 1.7f * v && v < 1.7f * u) { /* (1) */ + if (i == 1 && ns_attacks[chn][0] <= ns_attacks[chn][i]) { + ns_attacks[chn][0] = 0; + } + ns_attacks[chn][i] = 0; + } + } + } + + if (ns_attacks[chn][0] <= psv->last_attacks[chn]) { + ns_attacks[chn][0] = 0; + } + + if (psv->last_attacks[chn] == 3 || + ns_attacks[chn][0] + ns_attacks[chn][1] + ns_attacks[chn][2] + ns_attacks[chn][3]) { + ns_uselongblock = 0; + + if (ns_attacks[chn][1] && ns_attacks[chn][0]) { + ns_attacks[chn][1] = 0; + } + if (ns_attacks[chn][2] && ns_attacks[chn][1]) { + ns_attacks[chn][2] = 0; + } + if (ns_attacks[chn][3] && ns_attacks[chn][2]) { + ns_attacks[chn][3] = 0; + } + } + + if (chn < 2) { + uselongblock[chn] = ns_uselongblock; + } + else { + if (ns_uselongblock == 0) { + uselongblock[0] = uselongblock[1] = 0; + } + } + + /* there is a one granule delay. Copy maskings computed last call + * into masking_ratio to return to calling program. + */ + energy[chn] = psv->tot_ener[chn]; + } +} + + +static void +vbrpsy_skip_masking_s(lame_internal_flags * gfc, int chn, int sblock) +{ + if (sblock == 0) { + FLOAT *nbs2 = &gfc->sv_psy.nb_s2[chn][0]; + FLOAT *nbs1 = &gfc->sv_psy.nb_s1[chn][0]; + int const n = gfc->cd_psy->s.npart; + int b; + for (b = 0; b < n; b++) { + nbs2[b] = nbs1[b]; + } + } +} + + +static void +vbrpsy_calc_mask_index_s(lame_internal_flags const *gfc, FLOAT const *max, + FLOAT const *avg, unsigned char *mask_idx) +{ + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + FLOAT m, a; + int b, k; + int const last_tab_entry = dimension_of(tab) - 1; + b = 0; + a = avg[b] + avg[b + 1]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gds->numlines[b] + gds->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gds->numlines[b] + gds->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + + for (b = 1; b < gds->npart - 1; b++) { + a = avg[b - 1] + avg[b] + avg[b + 1]; + assert(b + 1 < gds->npart); + assert(a >= 0); + if (a > 0.0) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gds->numlines[b - 1] + gds->numlines[b] + gds->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 3.0f - a) + / (a * (gds->numlines[b - 1] + gds->numlines[b] + gds->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + } + assert(b > 0); + assert(b == gds->npart - 1); + + a = avg[b - 1] + avg[b]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + assert((gds->numlines[b - 1] + gds->numlines[b] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gds->numlines[b - 1] + gds->numlines[b] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + assert(b == (gds->npart - 1)); +} + + +static void +vbrpsy_compute_masking_s(lame_internal_flags * gfc, const FLOAT(*fftenergy_s)[HBLKSIZE_s], + FLOAT * eb, FLOAT * thr, int chn, int sblock) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + FLOAT max[CBANDS], avg[CBANDS]; + int i, j, b; + unsigned char mask_idx_s[CBANDS]; + + memset(max, 0, sizeof(max)); + memset(avg, 0, sizeof(avg)); + + for (b = j = 0; b < gds->npart; ++b) { + FLOAT ebb = 0, m = 0; + int const n = gds->numlines[b]; + for (i = 0; i < n; ++i, ++j) { + FLOAT const el = fftenergy_s[sblock][j]; + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + assert(ebb >= 0); + max[b] = m; + assert(n > 0); + avg[b] = ebb * gds->rnumlines[b]; + assert(avg[b] >= 0); + } + assert(b == gds->npart); + assert(j == 129); + vbrpsy_calc_mask_index_s(gfc, max, avg, mask_idx_s); + for (j = b = 0; b < gds->npart; b++) { + int kk = gds->s3ind[b][0]; + int const last = gds->s3ind[b][1]; + int const delta = mask_add_delta(mask_idx_s[b]); + int dd, dd_n; + FLOAT x, ecb, avg_mask; + FLOAT const masking_lower = gds->masking_lower[b] * gfc->sv_qnt.masking_lower; + + dd = mask_idx_s[kk]; + dd_n = 1; + ecb = gds->s3[j] * eb[kk] * tab[mask_idx_s[kk]]; + ++j, ++kk; + while (kk <= last) { + dd += mask_idx_s[kk]; + dd_n += 1; + x = gds->s3[j] * eb[kk] * tab[mask_idx_s[kk]]; + ecb = vbrpsy_mask_add(ecb, x, kk - b, delta); + ++j, ++kk; + } + dd = (1 + 2 * dd) / (2 * dd_n); + avg_mask = tab[dd] * 0.5f; + ecb *= avg_mask; +#if 0 /* we can do PRE ECHO control now here, or do it later */ + if (psv->blocktype_old[chn & 0x01] == SHORT_TYPE) { + /* limit calculated threshold by even older granule */ + FLOAT const t1 = rpelev_s * psv->nb_s1[chn][b]; + FLOAT const t2 = rpelev2_s * psv->nb_s2[chn][b]; + FLOAT const tm = (t2 > 0) ? Min(ecb, t2) : ecb; + thr[b] = (t1 > 0) ? NS_INTERP(Min(tm, t1), ecb, 0.6) : ecb; + } + else { + /* limit calculated threshold by older granule */ + FLOAT const t1 = rpelev_s * psv->nb_s1[chn][b]; + thr[b] = (t1 > 0) ? NS_INTERP(Min(ecb, t1), ecb, 0.6) : ecb; + } +#else /* we do it later */ + thr[b] = ecb; +#endif + psv->nb_s2[chn][b] = psv->nb_s1[chn][b]; + psv->nb_s1[chn][b] = ecb; + { + /* if THR exceeds EB, the quantization routines will take the difference + * from other bands. in case of strong tonal samples (tonaltest.wav) + * this leads to heavy distortions. that's why we limit THR here. + */ + x = max[b]; + x *= gds->minval[b]; + x *= avg_mask; + if (thr[b] > x) { + thr[b] = x; + } + } + if (masking_lower > 1) { + thr[b] *= masking_lower; + } + if (thr[b] > eb[b]) { + thr[b] = eb[b]; + } + if (masking_lower < 1) { + thr[b] *= masking_lower; + } + + assert(thr[b] >= 0); + } + for (; b < CBANDS; ++b) { + eb[b] = 0; + thr[b] = 0; + } +} + + +static void +vbrpsy_compute_masking_l(lame_internal_flags * gfc, const FLOAT fftenergy[HBLKSIZE], + FLOAT eb_l[CBANDS], FLOAT thr[CBANDS], int chn) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + FLOAT max[CBANDS], avg[CBANDS]; + unsigned char mask_idx_l[CBANDS + 2]; + int k, b; + + /********************************************************************* + * Calculate the energy and the tonality of each partition. + *********************************************************************/ + calc_energy(gdl, fftenergy, eb_l, max, avg); + calc_mask_index_l(gfc, max, avg, mask_idx_l); + + /********************************************************************* + * convolve the partitioned energy and unpredictability + * with the spreading function, s3_l[b][k] + ********************************************************************/ + k = 0; + for (b = 0; b < gdl->npart; b++) { + FLOAT x, ecb, avg_mask, t; + FLOAT const masking_lower = gdl->masking_lower[b] * gfc->sv_qnt.masking_lower; + /* convolve the partitioned energy with the spreading function */ + int kk = gdl->s3ind[b][0]; + int const last = gdl->s3ind[b][1]; + int const delta = mask_add_delta(mask_idx_l[b]); + int dd = 0, dd_n = 0; + + dd = mask_idx_l[kk]; + dd_n += 1; + ecb = gdl->s3[k] * eb_l[kk] * tab[mask_idx_l[kk]]; + ++k, ++kk; + while (kk <= last) { + dd += mask_idx_l[kk]; + dd_n += 1; + x = gdl->s3[k] * eb_l[kk] * tab[mask_idx_l[kk]]; + t = vbrpsy_mask_add(ecb, x, kk - b, delta); +#if 0 + ecb += eb_l[kk]; + if (ecb > t) { + ecb = t; + } +#else + ecb = t; +#endif + ++k, ++kk; + } + dd = (1 + 2 * dd) / (2 * dd_n); + avg_mask = tab[dd] * 0.5f; + ecb *= avg_mask; + + /**** long block pre-echo control ****/ + /* dont use long block pre-echo control if previous granule was + * a short block. This is to avoid the situation: + * frame0: quiet (very low masking) + * frame1: surge (triggers short blocks) + * frame2: regular frame. looks like pre-echo when compared to + * frame0, but all pre-echo was in frame1. + */ + /* chn=0,1 L and R channels + chn=2,3 S and M channels. + */ + if (psv->blocktype_old[chn & 0x01] == SHORT_TYPE) { + FLOAT const ecb_limit = rpelev * psv->nb_l1[chn][b]; + if (ecb_limit > 0) { + thr[b] = Min(ecb, ecb_limit); + } + else { + /* Robert 071209: + Because we don't calculate long block psy when we know a granule + should be of short blocks, we don't have any clue how the granule + before would have looked like as a long block. So we have to guess + a little bit for this END_TYPE block. + Most of the time we get away with this sloppyness. (fingers crossed :) + The speed increase is worth it. + */ + thr[b] = Min(ecb, eb_l[b] * NS_PREECHO_ATT2); + } + } + else { + FLOAT ecb_limit_2 = rpelev2 * psv->nb_l2[chn][b]; + FLOAT ecb_limit_1 = rpelev * psv->nb_l1[chn][b]; + FLOAT ecb_limit; + if (ecb_limit_2 <= 0) { + ecb_limit_2 = ecb; + } + if (ecb_limit_1 <= 0) { + ecb_limit_1 = ecb; + } + if (psv->blocktype_old[chn & 0x01] == NORM_TYPE) { + ecb_limit = Min(ecb_limit_1, ecb_limit_2); + } + else { + ecb_limit = ecb_limit_1; + } + thr[b] = Min(ecb, ecb_limit); + } + psv->nb_l2[chn][b] = psv->nb_l1[chn][b]; + psv->nb_l1[chn][b] = ecb; + { + /* if THR exceeds EB, the quantization routines will take the difference + * from other bands. in case of strong tonal samples (tonaltest.wav) + * this leads to heavy distortions. that's why we limit THR here. + */ + x = max[b]; + x *= gdl->minval[b]; + x *= avg_mask; + if (thr[b] > x) { + thr[b] = x; + } + } + if (masking_lower > 1) { + thr[b] *= masking_lower; + } + if (thr[b] > eb_l[b]) { + thr[b] = eb_l[b]; + } + if (masking_lower < 1) { + thr[b] *= masking_lower; + } + assert(thr[b] >= 0); + } + for (; b < CBANDS; ++b) { + eb_l[b] = 0; + thr[b] = 0; + } +} + + +static void +vbrpsy_compute_block_type(SessionConfig_t const *cfg, int *uselongblock) +{ + int chn; + + if (cfg->short_blocks == short_block_coupled + /* force both channels to use the same block type */ + /* this is necessary if the frame is to be encoded in ms_stereo. */ + /* But even without ms_stereo, FhG does this */ + && !(uselongblock[0] && uselongblock[1])) + uselongblock[0] = uselongblock[1] = 0; + + for (chn = 0; chn < cfg->channels_out; chn++) { + /* disable short blocks */ + if (cfg->short_blocks == short_block_dispensed) { + uselongblock[chn] = 1; + } + if (cfg->short_blocks == short_block_forced) { + uselongblock[chn] = 0; + } + } +} + + +static void +vbrpsy_apply_block_type(PsyStateVar_t * psv, int nch, int const *uselongblock, int *blocktype_d) +{ + int chn; + + /* update the blocktype of the previous granule, since it depends on what + * happend in this granule */ + for (chn = 0; chn < nch; chn++) { + int blocktype = NORM_TYPE; + /* disable short blocks */ + + if (uselongblock[chn]) { + /* no attack : use long blocks */ + assert(psv->blocktype_old[chn] != START_TYPE); + if (psv->blocktype_old[chn] == SHORT_TYPE) + blocktype = STOP_TYPE; + } + else { + /* attack : use short blocks */ + blocktype = SHORT_TYPE; + if (psv->blocktype_old[chn] == NORM_TYPE) { + psv->blocktype_old[chn] = START_TYPE; + } + if (psv->blocktype_old[chn] == STOP_TYPE) + psv->blocktype_old[chn] = SHORT_TYPE; + } + + blocktype_d[chn] = psv->blocktype_old[chn]; /* value returned to calling program */ + psv->blocktype_old[chn] = blocktype; /* save for next call to l3psy_anal */ + } +} + + +/*************************************************************** + * compute M/S thresholds from Johnston & Ferreira 1992 ICASSP paper + ***************************************************************/ + +static void +vbrpsy_compute_MS_thresholds(const FLOAT eb[4][CBANDS], FLOAT thr[4][CBANDS], + const FLOAT cb_mld[CBANDS], const FLOAT ath_cb[CBANDS], FLOAT athlower, + FLOAT msfix, int n) +{ + FLOAT const msfix2 = msfix * 2.f; + FLOAT rside, rmid; + int b; + for (b = 0; b < n; ++b) { + FLOAT const ebM = eb[2][b]; + FLOAT const ebS = eb[3][b]; + FLOAT const thmL = thr[0][b]; + FLOAT const thmR = thr[1][b]; + FLOAT thmM = thr[2][b]; + FLOAT thmS = thr[3][b]; + + /* use this fix if L & R masking differs by 2db or less */ + /* if db = 10*log10(x2/x1) < 2 */ + /* if (x2 < 1.58*x1) { */ + if (thmL <= 1.58f * thmR && thmR <= 1.58f * thmL) { + FLOAT const mld_m = cb_mld[b] * ebS; + FLOAT const mld_s = cb_mld[b] * ebM; + FLOAT const tmp_m = Min(thmS, mld_m); + FLOAT const tmp_s = Min(thmM, mld_s); + rmid = Max(thmM, tmp_m); + rside = Max(thmS, tmp_s); + } + else { + rmid = thmM; + rside = thmS; + } + if (msfix > 0.f) { + /***************************************************************/ + /* Adjust M/S maskings if user set "msfix" */ + /***************************************************************/ + /* Naoki Shibata 2000 */ + FLOAT thmLR, thmMS; + FLOAT const ath = ath_cb[b] * athlower; + FLOAT const tmp_l = Max(thmL, ath); + FLOAT const tmp_r = Max(thmR, ath); + thmLR = Min(tmp_l, tmp_r); + thmM = Max(rmid, ath); + thmS = Max(rside, ath); + thmMS = thmM + thmS; + if (thmMS > 0.f && (thmLR * msfix2) < thmMS) { + FLOAT const f = thmLR * msfix2 / thmMS; + thmM *= f; + thmS *= f; + assert(thmMS > 0.f); + } + rmid = Min(thmM, rmid); + rside = Min(thmS, rside); + } + if (rmid > ebM) { + rmid = ebM; + } + if (rside > ebS) { + rside = ebS; + } + thr[2][b] = rmid; + thr[3][b] = rside; + } +} + + +/* + * NOTE: the bitrate reduction from the inter-channel masking effect is low + * compared to the chance of getting annyoing artefacts. L3psycho_anal_vbr does + * not use this feature. (Robert 071216) +*/ + +int +L3psycho_anal_vbr(lame_internal_flags * gfc, + const sample_t * const buffer[2], int gr_out, + III_psy_ratio masking_ratio[2][2], + III_psy_ratio masking_MS_ratio[2][2], + FLOAT percep_entropy[2], FLOAT percep_MS_entropy[2], + FLOAT energy[4], int blocktype_d[2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + plotting_data *plt = cfg->analysis ? gfc->pinfo : 0; + + III_psy_xmin last_thm[4]; + + /* fft and energy calculation */ + FLOAT(*wsamp_l)[BLKSIZE]; + FLOAT(*wsamp_s)[3][BLKSIZE_s]; + FLOAT fftenergy[HBLKSIZE]; + FLOAT fftenergy_s[3][HBLKSIZE_s]; + FLOAT wsamp_L[2][BLKSIZE]; + FLOAT wsamp_S[2][3][BLKSIZE_s]; + FLOAT eb[4][CBANDS], thr[4][CBANDS]; + + FLOAT sub_short_factor[4][3]; + FLOAT thmm; + FLOAT const pcfact = 0.6f; + FLOAT const ath_factor = + (cfg->msfix > 0.f) ? (cfg->ATH_offset_factor * gfc->ATH->adjust_factor) : 1.f; + + const FLOAT(*const_eb)[CBANDS] = (const FLOAT(*)[CBANDS]) eb; + const FLOAT(*const_fftenergy_s)[HBLKSIZE_s] = (const FLOAT(*)[HBLKSIZE_s]) fftenergy_s; + + /* block type */ + int ns_attacks[4][4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} }; + int uselongblock[2]; + + /* usual variables like loop indices, etc.. */ + int chn, sb, sblock; + + /* chn=2 and 3 = Mid and Side channels */ + int const n_chn_psy = (cfg->mode == JOINT_STEREO) ? 4 : cfg->channels_out; + + memcpy(&last_thm[0], &psv->thm[0], sizeof(last_thm)); + + vbrpsy_attack_detection(gfc, buffer, gr_out, masking_ratio, masking_MS_ratio, energy, + sub_short_factor, ns_attacks, uselongblock); + + vbrpsy_compute_block_type(cfg, uselongblock); + + /* LONG BLOCK CASE */ + { + for (chn = 0; chn < n_chn_psy; chn++) { + int const ch01 = chn & 0x01; + + wsamp_l = wsamp_L + ch01; + vbrpsy_compute_fft_l(gfc, buffer, chn, gr_out, fftenergy, wsamp_l); + vbrpsy_compute_loudness_approximation_l(gfc, gr_out, chn, fftenergy); + vbrpsy_compute_masking_l(gfc, fftenergy, eb[chn], thr[chn], chn); + } + if (cfg->mode == JOINT_STEREO) { + if ((uselongblock[0] + uselongblock[1]) == 2) { + vbrpsy_compute_MS_thresholds(const_eb, thr, gdl->mld_cb, gfc->ATH->cb_l, + ath_factor, cfg->msfix, gdl->npart); + } + } + /* TODO: apply adaptive ATH masking here ?? */ + for (chn = 0; chn < n_chn_psy; chn++) { + convert_partition2scalefac_l(gfc, eb[chn], thr[chn], chn); + convert_partition2scalefac_l_to_s(gfc, eb[chn], thr[chn], chn); + } + } + /* SHORT BLOCKS CASE */ + { + int const force_short_block_calc = gfc->cd_psy->force_short_block_calc; + for (sblock = 0; sblock < 3; sblock++) { + for (chn = 0; chn < n_chn_psy; ++chn) { + int const ch01 = chn & 0x01; + if (uselongblock[ch01] && !force_short_block_calc) { + vbrpsy_skip_masking_s(gfc, chn, sblock); + } + else { + /* compute masking thresholds for short blocks */ + wsamp_s = wsamp_S + ch01; + vbrpsy_compute_fft_s(gfc, buffer, chn, sblock, fftenergy_s, wsamp_s); + vbrpsy_compute_masking_s(gfc, const_fftenergy_s, eb[chn], thr[chn], chn, + sblock); + } + } + if (cfg->mode == JOINT_STEREO) { + if ((uselongblock[0] + uselongblock[1]) == 0) { + vbrpsy_compute_MS_thresholds(const_eb, thr, gds->mld_cb, gfc->ATH->cb_s, + ath_factor, cfg->msfix, gds->npart); + } + } + /* TODO: apply adaptive ATH masking here ?? */ + for (chn = 0; chn < n_chn_psy; ++chn) { + int const ch01 = chn & 0x01; + if (!uselongblock[ch01] || force_short_block_calc) { + convert_partition2scalefac_s(gfc, eb[chn], thr[chn], chn, sblock); + } + } + } + + /**** short block pre-echo control ****/ + for (chn = 0; chn < n_chn_psy; chn++) { + for (sb = 0; sb < SBMAX_s; sb++) { + FLOAT new_thmm[3], prev_thm, t1, t2; + for (sblock = 0; sblock < 3; sblock++) { + thmm = psv->thm[chn].s[sb][sblock]; + thmm *= NS_PREECHO_ATT0; + + t1 = t2 = thmm; + + if (sblock > 0) { + prev_thm = new_thmm[sblock - 1]; + } + else { + prev_thm = last_thm[chn].s[sb][2]; + } + if (ns_attacks[chn][sblock] >= 2 || ns_attacks[chn][sblock + 1] == 1) { + t1 = NS_INTERP(prev_thm, thmm, NS_PREECHO_ATT1 * pcfact); + } + thmm = Min(t1, thmm); + if (ns_attacks[chn][sblock] == 1) { + t2 = NS_INTERP(prev_thm, thmm, NS_PREECHO_ATT2 * pcfact); + } + else if ((sblock == 0 && psv->last_attacks[chn] == 3) + || (sblock > 0 && ns_attacks[chn][sblock - 1] == 3)) { /* 2nd preceeding block */ + switch (sblock) { + case 0: + prev_thm = last_thm[chn].s[sb][1]; + break; + case 1: + prev_thm = last_thm[chn].s[sb][2]; + break; + case 2: + prev_thm = new_thmm[0]; + break; + } + t2 = NS_INTERP(prev_thm, thmm, NS_PREECHO_ATT2 * pcfact); + } + + thmm = Min(t1, thmm); + thmm = Min(t2, thmm); + + /* pulse like signal detection for fatboy.wav and so on */ + thmm *= sub_short_factor[chn][sblock]; + + new_thmm[sblock] = thmm; + } + for (sblock = 0; sblock < 3; sblock++) { + psv->thm[chn].s[sb][sblock] = new_thmm[sblock]; + } + } + } + } + for (chn = 0; chn < n_chn_psy; chn++) { + psv->last_attacks[chn] = ns_attacks[chn][2]; + } + + + /*************************************************************** + * determine final block type + ***************************************************************/ + vbrpsy_apply_block_type(psv, cfg->channels_out, uselongblock, blocktype_d); + + /********************************************************************* + * compute the value of PE to return ... no delay and advance + *********************************************************************/ + for (chn = 0; chn < n_chn_psy; chn++) { + FLOAT *ppe; + int type; + III_psy_ratio const *mr; + + if (chn > 1) { + ppe = percep_MS_entropy - 2; + type = NORM_TYPE; + if (blocktype_d[0] == SHORT_TYPE || blocktype_d[1] == SHORT_TYPE) + type = SHORT_TYPE; + mr = &masking_MS_ratio[gr_out][chn - 2]; + } + else { + ppe = percep_entropy; + type = blocktype_d[chn]; + mr = &masking_ratio[gr_out][chn]; + } + if (type == SHORT_TYPE) { + ppe[chn] = pecalc_s(mr, gfc->sv_qnt.masking_lower); + } + else { + ppe[chn] = pecalc_l(mr, gfc->sv_qnt.masking_lower); + } + + if (plt) { + plt->pe[gr_out][chn] = ppe[chn]; + } + } + return 0; +} + + + + +/* + * The spreading function. Values returned in units of energy + */ +static FLOAT +s3_func(FLOAT bark) +{ + FLOAT tempx, x, tempy, temp; + tempx = bark; + if (tempx >= 0) + tempx *= 3; + else + tempx *= 1.5; + + if (tempx >= 0.5 && tempx <= 2.5) { + temp = tempx - 0.5; + x = 8.0 * (temp * temp - 2.0 * temp); + } + else + x = 0.0; + tempx += 0.474; + tempy = 15.811389 + 7.5 * tempx - 17.5 * sqrt(1.0 + tempx * tempx); + + if (tempy <= -60.0) + return 0.0; + + tempx = exp((x + tempy) * LN_TO_LOG10); + + /* Normalization. The spreading function should be normalized so that: + +inf + / + | s3 [ bark ] d(bark) = 1 + / + -inf + */ + tempx /= .6609193; + return tempx; +} + +#if 0 +static FLOAT +norm_s3_func(void) +{ + double lim_a = 0, lim_b = 0; + double x = 0, l, h; + for (x = 0; s3_func(x) > 1e-20; x -= 1); + l = x; + h = 0; + while (fabs(h - l) > 1e-12) { + x = (h + l) / 2; + if (s3_func(x) > 0) { + h = x; + } + else { + l = x; + } + } + lim_a = l; + for (x = 0; s3_func(x) > 1e-20; x += 1); + l = 0; + h = x; + while (fabs(h - l) > 1e-12) { + x = (h + l) / 2; + if (s3_func(x) > 0) { + l = x; + } + else { + h = x; + } + } + lim_b = h; + { + double sum = 0; + int const m = 1000; + int i; + for (i = 0; i <= m; ++i) { + double x = lim_a + i * (lim_b - lim_a) / m; + double y = s3_func(x); + sum += y; + } + { + double norm = (m + 1) / (sum * (lim_b - lim_a)); + /*printf( "norm = %lf\n",norm); */ + return norm; + } + } +} +#endif + +static FLOAT +stereo_demask(double f) +{ + /* setup stereo demasking thresholds */ + /* formula reverse enginerred from plot in paper */ + double arg = freq2bark(f); + arg = (Min(arg, 15.5) / 15.5); + + return pow(10.0, 1.25 * (1 - cos(PI * arg)) - 2.5); +} + +static void +init_numline(PsyConst_CB2SB_t * gd, FLOAT sfreq, int fft_size, + int mdct_size, int sbmax, int const *scalepos) +{ + FLOAT b_frq[CBANDS + 1]; + FLOAT const mdct_freq_frac = sfreq / (2.0f * mdct_size); + FLOAT const deltafreq = fft_size / (2.0f * mdct_size); + int partition[HBLKSIZE] = { 0 }; + int i, j, ni; + int sfb; + sfreq /= fft_size; + j = 0; + ni = 0; + /* compute numlines, the number of spectral lines in each partition band */ + /* each partition band should be about DELBARK wide. */ + for (i = 0; i < CBANDS; i++) { + FLOAT bark1; + int j2, nl; + bark1 = freq2bark(sfreq * j); + + b_frq[i] = sfreq * j; + + for (j2 = j; freq2bark(sfreq * j2) - bark1 < DELBARK && j2 <= fft_size / 2; j2++); + + nl = j2 - j; + gd->numlines[i] = nl; + gd->rnumlines[i] = (nl > 0) ? (1.0f / nl) : 0; + + ni = i + 1; + + while (j < j2) { + assert(j < HBLKSIZE); + partition[j++] = i; + } + if (j > fft_size / 2) { + j = fft_size / 2; + ++i; + break; + } + } + assert(i < CBANDS); + b_frq[i] = sfreq * j; + + gd->n_sb = sbmax; + gd->npart = ni; + + { + j = 0; + for (i = 0; i < gd->npart; i++) { + int const nl = gd->numlines[i]; + FLOAT const freq = sfreq * (j + nl / 2); + gd->mld_cb[i] = stereo_demask(freq); + j += nl; + } + for (; i < CBANDS; ++i) { + gd->mld_cb[i] = 1; + } + } + for (sfb = 0; sfb < sbmax; sfb++) { + int i1, i2, bo; + int start = scalepos[sfb]; + int end = scalepos[sfb + 1]; + + i1 = floor(.5 + deltafreq * (start - .5)); + if (i1 < 0) + i1 = 0; + i2 = floor(.5 + deltafreq * (end - .5)); + + if (i2 > fft_size / 2) + i2 = fft_size / 2; + + bo = partition[i2]; + gd->bm[sfb] = (partition[i1] + partition[i2]) / 2; + gd->bo[sfb] = bo; + + /* calculate how much of this band belongs to current scalefactor band */ + { + FLOAT const f_tmp = mdct_freq_frac * end; + FLOAT bo_w = (f_tmp - b_frq[bo]) / (b_frq[bo + 1] - b_frq[bo]); + if (bo_w < 0) { + bo_w = 0; + } + else { + if (bo_w > 1) { + bo_w = 1; + } + } + gd->bo_weight[sfb] = bo_w; + } + gd->mld[sfb] = stereo_demask(mdct_freq_frac * start); + } +} + +static void +compute_bark_values(PsyConst_CB2SB_t const *gd, FLOAT sfreq, int fft_size, + FLOAT * bval, FLOAT * bval_width) +{ + /* compute bark values of each critical band */ + int k, j = 0, ni = gd->npart; + sfreq /= fft_size; + for (k = 0; k < ni; k++) { + int const w = gd->numlines[k]; + FLOAT bark1, bark2; + + bark1 = freq2bark(sfreq * (j)); + bark2 = freq2bark(sfreq * (j + w - 1)); + bval[k] = .5 * (bark1 + bark2); + + bark1 = freq2bark(sfreq * (j - .5)); + bark2 = freq2bark(sfreq * (j + w - .5)); + bval_width[k] = bark2 - bark1; + j += w; + } +} + +static int +init_s3_values(FLOAT ** p, int (*s3ind)[2], int npart, + FLOAT const *bval, FLOAT const *bval_width, FLOAT const *norm) +{ + FLOAT s3[CBANDS][CBANDS]; + /* The s3 array is not linear in the bark scale. + * bval[x] should be used to get the bark value. + */ + int i, j, k; + int numberOfNoneZero = 0; + + memset(&s3[0][0], 0, sizeof(s3)); + + /* s[i][j], the value of the spreading function, + * centered at band j (masker), for band i (maskee) + * + * i.e.: sum over j to spread into signal barkval=i + * NOTE: i and j are used opposite as in the ISO docs + */ + for (i = 0; i < npart; i++) { + for (j = 0; j < npart; j++) { + FLOAT v = s3_func(bval[i] - bval[j]) * bval_width[j]; + s3[i][j] = v * norm[i]; + } + } + for (i = 0; i < npart; i++) { + for (j = 0; j < npart; j++) { + if (s3[i][j] > 0.0f) + break; + } + s3ind[i][0] = j; + + for (j = npart - 1; j > 0; j--) { + if (s3[i][j] > 0.0f) + break; + } + s3ind[i][1] = j; + numberOfNoneZero += (s3ind[i][1] - s3ind[i][0] + 1); + } + *p = lame_calloc(FLOAT, numberOfNoneZero); + if (!*p) + return -1; + + k = 0; + for (i = 0; i < npart; i++) + for (j = s3ind[i][0]; j <= s3ind[i][1]; j++) + (*p)[k++] = s3[i][j]; + + return 0; +} + +int +psymodel_init(lame_global_flags const *gfp) +{ + lame_internal_flags *const gfc = gfp->internal_flags; + SessionConfig_t *const cfg = &gfc->cfg; + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_t *gd; + int i, j, b, sb, k; + FLOAT bvl_a = 13, bvl_b = 24; + FLOAT snr_l_a = 0, snr_l_b = 0; + FLOAT snr_s_a = -8.25, snr_s_b = -4.5; + + FLOAT bval[CBANDS]; + FLOAT bval_width[CBANDS]; + FLOAT norm[CBANDS]; + FLOAT const sfreq = cfg->samplerate_out; + + FLOAT xav = 10, xbv = 12; + FLOAT const minval_low = (0.f - cfg->minval); + + if (gfc->cd_psy != 0) { + return 0; + } + memset(norm, 0, sizeof(norm)); + + gd = lame_calloc(PsyConst_t, 1); + gfc->cd_psy = gd; + + gd->force_short_block_calc = gfp->experimentalZ; + + psv->blocktype_old[0] = psv->blocktype_old[1] = NORM_TYPE; /* the vbr header is long blocks */ + + for (i = 0; i < 4; ++i) { + for (j = 0; j < CBANDS; ++j) { + psv->nb_l1[i][j] = 1e20; + psv->nb_l2[i][j] = 1e20; + psv->nb_s1[i][j] = psv->nb_s2[i][j] = 1.0; + } + for (sb = 0; sb < SBMAX_l; sb++) { + psv->en[i].l[sb] = 1e20; + psv->thm[i].l[sb] = 1e20; + } + for (j = 0; j < 3; ++j) { + for (sb = 0; sb < SBMAX_s; sb++) { + psv->en[i].s[sb][j] = 1e20; + psv->thm[i].s[sb][j] = 1e20; + } + psv->last_attacks[i] = 0; + } + for (j = 0; j < 9; j++) + psv->last_en_subshort[i][j] = 10.; + } + + + /* init. for loudness approx. -jd 2001 mar 27 */ + psv->loudness_sq_save[0] = psv->loudness_sq_save[1] = 0.0; + + + + /************************************************************************* + * now compute the psychoacoustic model specific constants + ************************************************************************/ + /* compute numlines, bo, bm, bval, bval_width, mld */ + init_numline(&gd->l, sfreq, BLKSIZE, 576, SBMAX_l, gfc->scalefac_band.l); + assert(gd->l.npart < CBANDS); + compute_bark_values(&gd->l, sfreq, BLKSIZE, bval, bval_width); + + /* compute the spreading function */ + for (i = 0; i < gd->l.npart; i++) { + double snr = snr_l_a; + if (bval[i] >= bvl_a) { + snr = snr_l_b * (bval[i] - bvl_a) / (bvl_b - bvl_a) + + snr_l_a * (bvl_b - bval[i]) / (bvl_b - bvl_a); + } + norm[i] = pow(10.0, snr / 10.0); + } + i = init_s3_values(&gd->l.s3, gd->l.s3ind, gd->l.npart, bval, bval_width, norm); + if (i) + return i; + + /* compute long block specific values, ATH and MINVAL */ + j = 0; + for (i = 0; i < gd->l.npart; i++) { + double x; + + /* ATH */ + x = FLOAT_MAX; + for (k = 0; k < gd->l.numlines[i]; k++, j++) { + FLOAT const freq = sfreq * j / (1000.0 * BLKSIZE); + FLOAT level; + /* freq = Min(.1,freq); *//* ATH below 100 Hz constant, not further climbing */ + level = ATHformula(cfg, freq * 1000) - 20; /* scale to FFT units; returned value is in dB */ + level = pow(10., 0.1 * level); /* convert from dB -> energy */ + level *= gd->l.numlines[i]; + if (x > level) + x = level; + } + gfc->ATH->cb_l[i] = x; + + /* MINVAL. + For low freq, the strength of the masking is limited by minval + this is an ISO MPEG1 thing, dont know if it is really needed */ + /* FIXME: it does work to reduce low-freq problems in S53-Wind-Sax + and lead-voice samples, but introduces some 3 kbps bit bloat too. + TODO: Further refinement of the shape of this hack. + */ + x = 20.0 * (bval[i] / xav - 1.0); + if (x > 6) { + x = 30; + } + if (x < minval_low) { + x = minval_low; + } + if (cfg->samplerate_out < 44000) { + x = 30; + } + x -= 8.; + gd->l.minval[i] = pow(10.0, x / 10.) * gd->l.numlines[i]; + } + + /************************************************************************ + * do the same things for short blocks + ************************************************************************/ + init_numline(&gd->s, sfreq, BLKSIZE_s, 192, SBMAX_s, gfc->scalefac_band.s); + assert(gd->s.npart < CBANDS); + compute_bark_values(&gd->s, sfreq, BLKSIZE_s, bval, bval_width); + + /* SNR formula. short block is normalized by SNR. is it still right ? */ + j = 0; + for (i = 0; i < gd->s.npart; i++) { + double x; + double snr = snr_s_a; + if (bval[i] >= bvl_a) { + snr = snr_s_b * (bval[i] - bvl_a) / (bvl_b - bvl_a) + + snr_s_a * (bvl_b - bval[i]) / (bvl_b - bvl_a); + } + norm[i] = pow(10.0, snr / 10.0); + + /* ATH */ + x = FLOAT_MAX; + for (k = 0; k < gd->s.numlines[i]; k++, j++) { + FLOAT const freq = sfreq * j / (1000.0 * BLKSIZE_s); + FLOAT level; + /* freq = Min(.1,freq); *//* ATH below 100 Hz constant, not further climbing */ + level = ATHformula(cfg, freq * 1000) - 20; /* scale to FFT units; returned value is in dB */ + level = pow(10., 0.1 * level); /* convert from dB -> energy */ + level *= gd->s.numlines[i]; + if (x > level) + x = level; + } + gfc->ATH->cb_s[i] = x; + + /* MINVAL. + For low freq, the strength of the masking is limited by minval + this is an ISO MPEG1 thing, dont know if it is really needed */ + x = 7.0 * (bval[i] / xbv - 1.0); + if (bval[i] > xbv) { + x *= 1 + log(1 + x) * 3.1; + } + if (bval[i] < xbv) { + x *= 1 + log(1 - x) * 2.3; + } + if (x > 6) { + x = 30; + } + if (x < minval_low) { + x = minval_low; + } + if (cfg->samplerate_out < 44000) { + x = 30; + } + x -= 8; + gd->s.minval[i] = pow(10.0, x / 10) * gd->s.numlines[i]; + } + + i = init_s3_values(&gd->s.s3, gd->s.s3ind, gd->s.npart, bval, bval_width, norm); + if (i) + return i; + + + init_mask_add_max_values(); + init_fft(gfc); + + /* setup temporal masking */ + gd->decay = exp(-1.0 * LOG10 / (temporalmask_sustain_sec * sfreq / 192.0)); + + { + FLOAT msfix; + msfix = NS_MSFIX; + if (cfg->use_safe_joint_stereo) + msfix = 1.0; + if (fabs(cfg->msfix) > 0.0) + msfix = cfg->msfix; + cfg->msfix = msfix; + + /* spread only from npart_l bands. Normally, we use the spreading + * function to convolve from npart_l down to npart_l bands + */ + for (b = 0; b < gd->l.npart; b++) + if (gd->l.s3ind[b][1] > gd->l.npart - 1) + gd->l.s3ind[b][1] = gd->l.npart - 1; + } + + /* prepare for ATH auto adjustment: + * we want to decrease the ATH by 12 dB per second + */ +#define frame_duration (576. * cfg->mode_gr / sfreq) + gfc->ATH->decay = pow(10., -12. / 10. * frame_duration); + gfc->ATH->adjust_factor = 0.01; /* minimum, for leading low loudness */ + gfc->ATH->adjust_limit = 1.0; /* on lead, allow adjust up to maximum */ +#undef frame_duration + + assert(gd->l.bo[SBMAX_l - 1] <= gd->l.npart); + assert(gd->s.bo[SBMAX_s - 1] <= gd->s.npart); + + if (cfg->ATHtype != -1) { + /* compute equal loudness weights (eql_w) */ + FLOAT freq; + FLOAT const freq_inc = (FLOAT) cfg->samplerate_out / (FLOAT) (BLKSIZE); + FLOAT eql_balance = 0.0; + freq = 0.0; + for (i = 0; i < BLKSIZE / 2; ++i) { + /* convert ATH dB to relative power (not dB) */ + /* to determine eql_w */ + freq += freq_inc; + gfc->ATH->eql_w[i] = 1. / pow(10, ATHformula(cfg, freq) / 10); + eql_balance += gfc->ATH->eql_w[i]; + } + eql_balance = 1.0 / eql_balance; + for (i = BLKSIZE / 2; --i >= 0;) { /* scale weights */ + gfc->ATH->eql_w[i] *= eql_balance; + } + } + { + for (b = j = 0; b < gd->s.npart; ++b) { + for (i = 0; i < gd->s.numlines[b]; ++i) { + ++j; + } + } + assert(j == 129); + for (b = j = 0; b < gd->l.npart; ++b) { + for (i = 0; i < gd->l.numlines[b]; ++i) { + ++j; + } + } + assert(j == 513); + } + /* short block attack threshold */ + { + float x = gfp->attackthre; + float y = gfp->attackthre_s; + if (x < 0) { + x = NSATTACKTHRE; + } + if (y < 0) { + y = NSATTACKTHRE_S; + } + gd->attack_threshold[0] = gd->attack_threshold[1] = gd->attack_threshold[2] = x; + gd->attack_threshold[3] = y; + } + { + float sk_s = -10.f, sk_l = -4.7f; + static float const sk[] = + { -7.4, -7.4, -7.4, -9.5, -7.4, -6.1, -5.5, -4.7, -4.7, -4.7, -4.7 }; + if (gfp->VBR_q < 4) { + sk_l = sk_s = sk[0]; + } + else { + sk_l = sk_s = sk[gfp->VBR_q] + gfp->VBR_q_frac * (sk[gfp->VBR_q] - sk[gfp->VBR_q + 1]); + } + b = 0; + for (; b < gd->s.npart; b++) { + float m = (float) (gd->s.npart - b) / gd->s.npart; + gd->s.masking_lower[b] = powf(10.f, sk_s * m * 0.1f); + } + for (; b < CBANDS; ++b) { + gd->s.masking_lower[b] = 1.f; + } + b = 0; + for (; b < gd->l.npart; b++) { + float m = (float) (gd->l.npart - b) / gd->l.npart; + gd->l.masking_lower[b] = powf(10.f, sk_l * m * 0.1f); + } + for (; b < CBANDS; ++b) { + gd->l.masking_lower[b] = 1.f; + } + } + memcpy(&gd->l_to_s, &gd->l, sizeof(gd->l_to_s)); + init_numline(&gd->l_to_s, sfreq, BLKSIZE, 192, SBMAX_s, gfc->scalefac_band.s); + return 0; +} diff --git a/pkg/lame/clame/psymodel.h b/pkg/lame/clame/psymodel.h new file mode 100644 index 0000000..f46083c --- /dev/null +++ b/pkg/lame/clame/psymodel.h @@ -0,0 +1,64 @@ +/* + * psymodel.h + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_PSYMODEL_H +#define LAME_PSYMODEL_H + + +int L3psycho_anal_ns(lame_internal_flags * gfc, + const sample_t *const buffer[2], int gr, + III_psy_ratio ratio[2][2], + III_psy_ratio MS_ratio[2][2], + FLOAT pe[2], FLOAT pe_MS[2], FLOAT ener[2], int blocktype_d[2]); + +int L3psycho_anal_vbr(lame_internal_flags * gfc, + const sample_t *const buffer[2], int gr, + III_psy_ratio ratio[2][2], + III_psy_ratio MS_ratio[2][2], + FLOAT pe[2], FLOAT pe_MS[2], FLOAT ener[2], int blocktype_d[2]); + + +int psymodel_init(lame_global_flags const* gfp); + + +#define rpelev 2 +#define rpelev2 16 +#define rpelev_s 2 +#define rpelev2_s 16 + +/* size of each partition band, in barks: */ +#define DELBARK .34 + + +/* tuned for output level (sensitive to energy scale) */ +#define VO_SCALE (1./( 14752*14752 )/(BLKSIZE/2)) + +#define temporalmask_sustain_sec 0.01 + +#define NS_PREECHO_ATT0 0.8 +#define NS_PREECHO_ATT1 0.6 +#define NS_PREECHO_ATT2 0.3 + +#define NS_MSFIX 3.5 +#define NSATTACKTHRE 4.4 +#define NSATTACKTHRE_S 25 + +#endif /* LAME_PSYMODEL_H */ diff --git a/pkg/lame/clame/quantize.c b/pkg/lame/clame/quantize.c new file mode 100644 index 0000000..9ba9c16 --- /dev/null +++ b/pkg/lame/clame/quantize.c @@ -0,0 +1,2050 @@ +/* + * MP3 quantization + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 1999-2003 Takehiro Tominaga + * Copyright (c) 2000-2011 Robert Hegemann + * Copyright (c) 2001-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: quantize.c,v 1.219 2017/08/02 19:48:05 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "quantize_pvt.h" +#include "reservoir.h" +#include "bitstream.h" +#include "vbrquantize.h" +#include "quantize.h" +#ifdef HAVE_XMMINTRIN_H +#include "vector/lame_intrin.h" +#endif + + + + +/* convert from L/R <-> Mid/Side */ +static void +ms_convert(III_side_info_t * l3_side, int gr) +{ + int i; + for (i = 0; i < 576; ++i) { + FLOAT l, r; + l = l3_side->tt[gr][0].xr[i]; + r = l3_side->tt[gr][1].xr[i]; + l3_side->tt[gr][0].xr[i] = (l + r) * (FLOAT) (SQRT2 * 0.5); + l3_side->tt[gr][1].xr[i] = (l - r) * (FLOAT) (SQRT2 * 0.5); + } +} + +/************************************************************************ + * + * init_outer_loop() + * mt 6/99 + * + * initializes cod_info, scalefac and xrpow + * + * returns 0 if all energies in xr are zero, else 1 + * + ************************************************************************/ + +static void +init_xrpow_core_c(gr_info * const cod_info, FLOAT xrpow[576], int upper, FLOAT * sum) +{ + int i; + FLOAT tmp; + *sum = 0; + for (i = 0; i <= upper; ++i) { + tmp = fabs(cod_info->xr[i]); + *sum += tmp; + xrpow[i] = sqrt(tmp * sqrt(tmp)); + + if (xrpow[i] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[i]; + } +} + + + + + +void +init_xrpow_core_init(lame_internal_flags * const gfc) +{ + gfc->init_xrpow_core = init_xrpow_core_c; + +#if defined(HAVE_XMMINTRIN_H) + if (gfc->CPU_features.SSE) + gfc->init_xrpow_core = init_xrpow_core_sse; +#endif +#ifndef HAVE_NASM +#ifdef MIN_ARCH_SSE + gfc->init_xrpow_core = init_xrpow_core_sse; +#endif +#endif +} + + + +static int +init_xrpow(lame_internal_flags * gfc, gr_info * const cod_info, FLOAT xrpow[576]) +{ + FLOAT sum = 0; + int i; + int const upper = cod_info->max_nonzero_coeff; + + assert(xrpow != NULL); + cod_info->xrpow_max = 0; + + /* check if there is some energy we have to quantize + * and calculate xrpow matching our fresh scalefactors + */ + assert(0 <= upper && upper <= 575); + memset(&(xrpow[upper]), 0, (576 - upper) * sizeof(xrpow[0])); + + + gfc->init_xrpow_core(cod_info, xrpow, upper, &sum); + + /* return 1 if we have something to quantize, else 0 + */ + if (sum > (FLOAT) 1E-20) { + int j = 0; + if (gfc->sv_qnt.substep_shaping & 2) + j = 1; + + for (i = 0; i < cod_info->psymax; i++) + gfc->sv_qnt.pseudohalf[i] = j; + + return 1; + } + + memset(&cod_info->l3_enc[0], 0, sizeof(int) * 576); + return 0; +} + + + + + +/* +Gabriel Bouvigne feb/apr 2003 +Analog silence detection in partitionned sfb21 +or sfb12 for short blocks + +From top to bottom of sfb, changes to 0 +coeffs which are below ath. It stops on the first +coeff higher than ath. +*/ +static void +psfb21_analogsilence(lame_internal_flags const *gfc, gr_info * const cod_info) +{ + ATH_t const *const ATH = gfc->ATH; + FLOAT *const xr = cod_info->xr; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type, but not SHORT blocks */ + int gsfb; + int stop = 0; + for (gsfb = PSFB21 - 1; gsfb >= 0 && !stop; gsfb--) { + int const start = gfc->scalefac_band.psfb21[gsfb]; + int const end = gfc->scalefac_band.psfb21[gsfb + 1]; + int j; + FLOAT ath21; + ath21 = athAdjust(ATH->adjust_factor, ATH->psfb21[gsfb], ATH->floor, 0); + + if (gfc->sv_qnt.longfact[21] > 1e-12f) + ath21 *= gfc->sv_qnt.longfact[21]; + + for (j = end - 1; j >= start; j--) { + if (fabs(xr[j]) < ath21) + xr[j] = 0; + else { + stop = 1; + break; + } + } + } + } + else { + /*note: short blocks coeffs are reordered */ + int block; + for (block = 0; block < 3; block++) { + + int gsfb; + int stop = 0; + for (gsfb = PSFB12 - 1; gsfb >= 0 && !stop; gsfb--) { + int const start = gfc->scalefac_band.s[12] * 3 + + (gfc->scalefac_band.s[13] - gfc->scalefac_band.s[12]) * block + + (gfc->scalefac_band.psfb12[gsfb] - gfc->scalefac_band.psfb12[0]); + int const end = + start + (gfc->scalefac_band.psfb12[gsfb + 1] - gfc->scalefac_band.psfb12[gsfb]); + int j; + FLOAT ath12; + ath12 = athAdjust(ATH->adjust_factor, ATH->psfb12[gsfb], ATH->floor, 0); + + if (gfc->sv_qnt.shortfact[12] > 1e-12f) + ath12 *= gfc->sv_qnt.shortfact[12]; + + for (j = end - 1; j >= start; j--) { + if (fabs(xr[j]) < ath12) + xr[j] = 0; + else { + stop = 1; + break; + } + } + } + } + } + +} + + + + + +static void +init_outer_loop(lame_internal_flags const *gfc, gr_info * const cod_info) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfb, j; + /* initialize fresh cod_info + */ + cod_info->part2_3_length = 0; + cod_info->big_values = 0; + cod_info->count1 = 0; + cod_info->global_gain = 210; + cod_info->scalefac_compress = 0; + /* mixed_block_flag, block_type was set in psymodel.c */ + cod_info->table_select[0] = 0; + cod_info->table_select[1] = 0; + cod_info->table_select[2] = 0; + cod_info->subblock_gain[0] = 0; + cod_info->subblock_gain[1] = 0; + cod_info->subblock_gain[2] = 0; + cod_info->subblock_gain[3] = 0; /* this one is always 0 */ + cod_info->region0_count = 0; + cod_info->region1_count = 0; + cod_info->preflag = 0; + cod_info->scalefac_scale = 0; + cod_info->count1table_select = 0; + cod_info->part2_length = 0; + if (cfg->samplerate_out <= 8000) { + cod_info->sfb_lmax = 17; + cod_info->sfb_smin = 9; + cod_info->psy_lmax = 17; + } + else { + cod_info->sfb_lmax = SBPSY_l; + cod_info->sfb_smin = SBPSY_s; + cod_info->psy_lmax = gfc->sv_qnt.sfb21_extra ? SBMAX_l : SBPSY_l; + } + cod_info->psymax = cod_info->psy_lmax; + cod_info->sfbmax = cod_info->sfb_lmax; + cod_info->sfbdivide = 11; + for (sfb = 0; sfb < SBMAX_l; sfb++) { + cod_info->width[sfb] + = gfc->scalefac_band.l[sfb + 1] - gfc->scalefac_band.l[sfb]; + cod_info->window[sfb] = 3; /* which is always 0. */ + } + if (cod_info->block_type == SHORT_TYPE) { + FLOAT ixwork[576]; + FLOAT *ix; + + cod_info->sfb_smin = 0; + cod_info->sfb_lmax = 0; + if (cod_info->mixed_block_flag) { + /* + * MPEG-1: sfbs 0-7 long block, 3-12 short blocks + * MPEG-2(.5): sfbs 0-5 long block, 3-12 short blocks + */ + cod_info->sfb_smin = 3; + cod_info->sfb_lmax = cfg->mode_gr * 2 + 4; + } + if (cfg->samplerate_out <= 8000) { + cod_info->psymax + = cod_info->sfb_lmax + + 3 * (9 - cod_info->sfb_smin); + cod_info->sfbmax = cod_info->sfb_lmax + 3 * (9 - cod_info->sfb_smin); + } + else { + cod_info->psymax + = cod_info->sfb_lmax + + 3 * ((gfc->sv_qnt.sfb21_extra ? SBMAX_s : SBPSY_s) - cod_info->sfb_smin); + cod_info->sfbmax = cod_info->sfb_lmax + 3 * (SBPSY_s - cod_info->sfb_smin); + } + cod_info->sfbdivide = cod_info->sfbmax - 18; + cod_info->psy_lmax = cod_info->sfb_lmax; + /* re-order the short blocks, for more efficient encoding below */ + /* By Takehiro TOMINAGA */ + /* + Within each scalefactor band, data is given for successive + time windows, beginning with window 0 and ending with window 2. + Within each window, the quantized values are then arranged in + order of increasing frequency... + */ + ix = &cod_info->xr[gfc->scalefac_band.l[cod_info->sfb_lmax]]; + memcpy(ixwork, cod_info->xr, 576 * sizeof(FLOAT)); + for (sfb = cod_info->sfb_smin; sfb < SBMAX_s; sfb++) { + int const start = gfc->scalefac_band.s[sfb]; + int const end = gfc->scalefac_band.s[sfb + 1]; + int window, l; + for (window = 0; window < 3; window++) { + for (l = start; l < end; l++) { + *ix++ = ixwork[3 * l + window]; + } + } + } + + j = cod_info->sfb_lmax; + for (sfb = cod_info->sfb_smin; sfb < SBMAX_s; sfb++) { + cod_info->width[j] = cod_info->width[j + 1] = cod_info->width[j + 2] + = gfc->scalefac_band.s[sfb + 1] - gfc->scalefac_band.s[sfb]; + cod_info->window[j] = 0; + cod_info->window[j + 1] = 1; + cod_info->window[j + 2] = 2; + j += 3; + } + } + + cod_info->count1bits = 0; + cod_info->sfb_partition_table = nr_of_sfb_block[0][0]; + cod_info->slen[0] = 0; + cod_info->slen[1] = 0; + cod_info->slen[2] = 0; + cod_info->slen[3] = 0; + + cod_info->max_nonzero_coeff = 575; + + /* fresh scalefactors are all zero + */ + memset(cod_info->scalefac, 0, sizeof(cod_info->scalefac)); + + if (cfg->vbr != vbr_mt && cfg->vbr != vbr_mtrh && cfg->vbr != vbr_abr && cfg->vbr != vbr_off) { + psfb21_analogsilence(gfc, cod_info); + } +} + + + +/************************************************************************ + * + * bin_search_StepSize() + * + * author/date?? + * + * binary step size search + * used by outer_loop to get a quantizer step size to start with + * + ************************************************************************/ + +typedef enum { + BINSEARCH_NONE, + BINSEARCH_UP, + BINSEARCH_DOWN +} binsearchDirection_t; + +static int +bin_search_StepSize(lame_internal_flags * const gfc, gr_info * const cod_info, + int desired_rate, const int ch, const FLOAT xrpow[576]) +{ + int nBits; + int CurrentStep = gfc->sv_qnt.CurrentStep[ch]; + int flag_GoneOver = 0; + int const start = gfc->sv_qnt.OldValue[ch]; + binsearchDirection_t Direction = BINSEARCH_NONE; + cod_info->global_gain = start; + desired_rate -= cod_info->part2_length; + + assert(CurrentStep); + for (;;) { + int step; + nBits = count_bits(gfc, xrpow, cod_info, 0); + + if (CurrentStep == 1 || nBits == desired_rate) + break; /* nothing to adjust anymore */ + + if (nBits > desired_rate) { + /* increase Quantize_StepSize */ + if (Direction == BINSEARCH_DOWN) + flag_GoneOver = 1; + + if (flag_GoneOver) + CurrentStep /= 2; + Direction = BINSEARCH_UP; + step = CurrentStep; + } + else { + /* decrease Quantize_StepSize */ + if (Direction == BINSEARCH_UP) + flag_GoneOver = 1; + + if (flag_GoneOver) + CurrentStep /= 2; + Direction = BINSEARCH_DOWN; + step = -CurrentStep; + } + cod_info->global_gain += step; + if (cod_info->global_gain < 0) { + cod_info->global_gain = 0; + flag_GoneOver = 1; + } + if (cod_info->global_gain > 255) { + cod_info->global_gain = 255; + flag_GoneOver = 1; + } + } + + assert(cod_info->global_gain >= 0); + assert(cod_info->global_gain < 256); + + while (nBits > desired_rate && cod_info->global_gain < 255) { + cod_info->global_gain++; + nBits = count_bits(gfc, xrpow, cod_info, 0); + } + gfc->sv_qnt.CurrentStep[ch] = (start - cod_info->global_gain >= 4) ? 4 : 2; + gfc->sv_qnt.OldValue[ch] = cod_info->global_gain; + cod_info->part2_3_length = nBits; + return nBits; +} + + + + +/************************************************************************ + * + * trancate_smallspectrums() + * + * Takehiro TOMINAGA 2002-07-21 + * + * trancate smaller nubmers into 0 as long as the noise threshold is allowed. + * + ************************************************************************/ +static int +floatcompare(const void *v1, const void *v2) +{ + const FLOAT *const a = v1, *const b = v2; + if (*a > *b) + return 1; + if (*a < *b) + return -1; + return 0; +} + +static void +trancate_smallspectrums(lame_internal_flags const *gfc, + gr_info * const gi, const FLOAT * const l3_xmin, FLOAT * const work) +{ + int sfb, j, width; + FLOAT distort[SFBMAX]; + calc_noise_result dummy; + + if ((!(gfc->sv_qnt.substep_shaping & 4) && gi->block_type == SHORT_TYPE) + || gfc->sv_qnt.substep_shaping & 0x80) + return; + (void) calc_noise(gi, l3_xmin, distort, &dummy, 0); + for (j = 0; j < 576; j++) { + FLOAT xr = 0.0; + if (gi->l3_enc[j] != 0) + xr = fabs(gi->xr[j]); + work[j] = xr; + } + + j = 0; + sfb = 8; + if (gi->block_type == SHORT_TYPE) + sfb = 6; + do { + FLOAT allowedNoise, trancateThreshold; + int nsame, start; + + width = gi->width[sfb]; + j += width; + if (distort[sfb] >= 1.0) + continue; + + qsort(&work[j - width], width, sizeof(FLOAT), floatcompare); + if (EQ(work[j - 1], 0.0)) + continue; /* all zero sfb */ + + allowedNoise = (1.0 - distort[sfb]) * l3_xmin[sfb]; + trancateThreshold = 0.0; + start = 0; + do { + FLOAT noise; + for (nsame = 1; start + nsame < width; nsame++) + if (NEQ(work[start + j - width], work[start + j + nsame - width])) + break; + + noise = work[start + j - width] * work[start + j - width] * nsame; + if (allowedNoise < noise) { + if (start != 0) + trancateThreshold = work[start + j - width - 1]; + break; + } + allowedNoise -= noise; + start += nsame; + } while (start < width); + if (EQ(trancateThreshold, 0.0)) + continue; + +/* printf("%e %e %e\n", */ +/* trancateThreshold/l3_xmin[sfb], */ +/* trancateThreshold/(l3_xmin[sfb]*start), */ +/* trancateThreshold/(l3_xmin[sfb]*(start+width)) */ +/* ); */ +/* if (trancateThreshold > 1000*l3_xmin[sfb]*start) */ +/* trancateThreshold = 1000*l3_xmin[sfb]*start; */ + + do { + if (fabs(gi->xr[j - width]) <= trancateThreshold) + gi->l3_enc[j - width] = 0; + } while (--width > 0); + } while (++sfb < gi->psymax); + + gi->part2_3_length = noquant_count_bits(gfc, gi, 0); +} + + +/************************************************************************* + * + * loop_break() + * + * author/date?? + * + * Function: Returns zero if there is a scalefac which has not been + * amplified. Otherwise it returns one. + * + *************************************************************************/ + +inline static int +loop_break(const gr_info * const cod_info) +{ + int sfb; + + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) + if (cod_info->scalefac[sfb] + + cod_info->subblock_gain[cod_info->window[sfb]] == 0) + return 0; + + return 1; +} + + + + +/* mt 5/99: Function: Improved calc_noise for a single channel */ + +/************************************************************************* + * + * quant_compare() + * + * author/date?? + * + * several different codes to decide which quantization is better + * + *************************************************************************/ + +static double +penalties(double noise) +{ + return FAST_LOG10(0.368 + 0.632 * noise * noise * noise); +} + +static double +get_klemm_noise(const FLOAT * distort, const gr_info * const gi) +{ + int sfb; + double klemm_noise = 1E-37; + for (sfb = 0; sfb < gi->psymax; sfb++) + klemm_noise += penalties(distort[sfb]); + + return Max(1e-20, klemm_noise); +} + +inline static int +quant_compare(const int quant_comp, + const calc_noise_result * const best, + calc_noise_result * const calc, const gr_info * const gi, const FLOAT * distort) +{ + /* + noise is given in decibels (dB) relative to masking thesholds. + + over_noise: ??? (the previous comment is fully wrong) + tot_noise: ??? (the previous comment is fully wrong) + max_noise: max quantization noise + + */ + int better; + + switch (quant_comp) { + default: + case 9:{ + if (best->over_count > 0) { + /* there are distorted sfb */ + better = calc->over_SSD <= best->over_SSD; + if (calc->over_SSD == best->over_SSD) + better = calc->bits < best->bits; + } + else { + /* no distorted sfb */ + better = ((calc->max_noise < 0) && + ((calc->max_noise * 10 + calc->bits) <= + (best->max_noise * 10 + best->bits))); + } + break; + } + + case 0: + better = calc->over_count < best->over_count + || (calc->over_count == best->over_count && calc->over_noise < best->over_noise) + || (calc->over_count == best->over_count && + EQ(calc->over_noise, best->over_noise) && calc->tot_noise < best->tot_noise); + break; + + case 8: + calc->max_noise = get_klemm_noise(distort, gi); + /*lint --fallthrough */ + case 1: + better = calc->max_noise < best->max_noise; + break; + case 2: + better = calc->tot_noise < best->tot_noise; + break; + case 3: + better = (calc->tot_noise < best->tot_noise) + && (calc->max_noise < best->max_noise); + break; + case 4: + better = (calc->max_noise <= 0.0 && best->max_noise > 0.2) + || (calc->max_noise <= 0.0 && + best->max_noise < 0.0 && + best->max_noise > calc->max_noise - 0.2 && calc->tot_noise < best->tot_noise) + || (calc->max_noise <= 0.0 && + best->max_noise > 0.0 && + best->max_noise > calc->max_noise - 0.2 && + calc->tot_noise < best->tot_noise + best->over_noise) + || (calc->max_noise > 0.0 && + best->max_noise > -0.05 && + best->max_noise > calc->max_noise - 0.1 && + calc->tot_noise + calc->over_noise < best->tot_noise + best->over_noise) + || (calc->max_noise > 0.0 && + best->max_noise > -0.1 && + best->max_noise > calc->max_noise - 0.15 && + calc->tot_noise + calc->over_noise + calc->over_noise < + best->tot_noise + best->over_noise + best->over_noise); + break; + case 5: + better = calc->over_noise < best->over_noise + || (EQ(calc->over_noise, best->over_noise) && calc->tot_noise < best->tot_noise); + break; + case 6: + better = calc->over_noise < best->over_noise + || (EQ(calc->over_noise, best->over_noise) && + (calc->max_noise < best->max_noise + || (EQ(calc->max_noise, best->max_noise) && calc->tot_noise <= best->tot_noise) + )); + break; + case 7: + better = calc->over_count < best->over_count || calc->over_noise < best->over_noise; + break; + } + + + if (best->over_count == 0) { + /* + If no distorted bands, only use this quantization + if it is better, and if it uses less bits. + Unfortunately, part2_3_length is sometimes a poor + estimator of the final size at low bitrates. + */ + better = better && calc->bits < best->bits; + } + + + return better; +} + + + +/************************************************************************* + * + * amp_scalefac_bands() + * + * author/date?? + * + * Amplify the scalefactor bands that violate the masking threshold. + * See ISO 11172-3 Section C.1.5.4.3.5 + * + * distort[] = noise/masking + * distort[] > 1 ==> noise is not masked + * distort[] < 1 ==> noise is masked + * max_dist = maximum value of distort[] + * + * Three algorithms: + * noise_shaping_amp + * 0 Amplify all bands with distort[]>1. + * + * 1 Amplify all bands with distort[] >= max_dist^(.5); + * ( 50% in the db scale) + * + * 2 Amplify first band with distort[] >= max_dist; + * + * + * For algorithms 0 and 1, if max_dist < 1, then amplify all bands + * with distort[] >= .95*max_dist. This is to make sure we always + * amplify at least one band. + * + * + *************************************************************************/ +static void +amp_scalefac_bands(lame_internal_flags * gfc, + gr_info * const cod_info, FLOAT const *distort, FLOAT xrpow[576], int bRefine) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int j, sfb; + FLOAT ifqstep34, trigger; + int noise_shaping_amp; + + if (cod_info->scalefac_scale == 0) { + ifqstep34 = 1.29683955465100964055; /* 2**(.75*.5) */ + } + else { + ifqstep34 = 1.68179283050742922612; /* 2**(.75*1) */ + } + + /* compute maximum value of distort[] */ + trigger = 0; + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) { + if (trigger < distort[sfb]) + trigger = distort[sfb]; + } + + noise_shaping_amp = cfg->noise_shaping_amp; + if (noise_shaping_amp == 3) { + if (bRefine == 1) + noise_shaping_amp = 2; + else + noise_shaping_amp = 1; + } + switch (noise_shaping_amp) { + case 2: + /* amplify exactly 1 band */ + break; + + case 1: + /* amplify bands within 50% of max (on db scale) */ + if (trigger > 1.0) + trigger = pow(trigger, .5); + else + trigger *= .95; + break; + + case 0: + default: + /* ISO algorithm. amplify all bands with distort>1 */ + if (trigger > 1.0) + trigger = 1.0; + else + trigger *= .95; + break; + } + + j = 0; + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) { + int const width = cod_info->width[sfb]; + int l; + j += width; + if (distort[sfb] < trigger) + continue; + + if (gfc->sv_qnt.substep_shaping & 2) { + gfc->sv_qnt.pseudohalf[sfb] = !gfc->sv_qnt.pseudohalf[sfb]; + if (!gfc->sv_qnt.pseudohalf[sfb] && cfg->noise_shaping_amp == 2) + return; + } + cod_info->scalefac[sfb]++; + for (l = -width; l < 0; l++) { + xrpow[j + l] *= ifqstep34; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + + if (cfg->noise_shaping_amp == 2) + return; + } +} + +/************************************************************************* + * + * inc_scalefac_scale() + * + * Takehiro Tominaga 2000-xx-xx + * + * turns on scalefac scale and adjusts scalefactors + * + *************************************************************************/ + +static void +inc_scalefac_scale(gr_info * const cod_info, FLOAT xrpow[576]) +{ + int l, j, sfb; + const FLOAT ifqstep34 = 1.29683955465100964055; + + j = 0; + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) { + int const width = cod_info->width[sfb]; + int s = cod_info->scalefac[sfb]; + if (cod_info->preflag) + s += pretab[sfb]; + j += width; + if (s & 1) { + s++; + for (l = -width; l < 0; l++) { + xrpow[j + l] *= ifqstep34; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + } + cod_info->scalefac[sfb] = s >> 1; + } + cod_info->preflag = 0; + cod_info->scalefac_scale = 1; +} + + + +/************************************************************************* + * + * inc_subblock_gain() + * + * Takehiro Tominaga 2000-xx-xx + * + * increases the subblock gain and adjusts scalefactors + * + *************************************************************************/ + +static int +inc_subblock_gain(const lame_internal_flags * const gfc, gr_info * const cod_info, FLOAT xrpow[576]) +{ + int sfb, window; + int *const scalefac = cod_info->scalefac; + + /* subbloc_gain can't do anything in the long block region */ + for (sfb = 0; sfb < cod_info->sfb_lmax; sfb++) { + if (scalefac[sfb] >= 16) + return 1; + } + + for (window = 0; window < 3; window++) { + int s1, s2, l, j; + s1 = s2 = 0; + + for (sfb = cod_info->sfb_lmax + window; sfb < cod_info->sfbdivide; sfb += 3) { + if (s1 < scalefac[sfb]) + s1 = scalefac[sfb]; + } + for (; sfb < cod_info->sfbmax; sfb += 3) { + if (s2 < scalefac[sfb]) + s2 = scalefac[sfb]; + } + + if (s1 < 16 && s2 < 8) + continue; + + if (cod_info->subblock_gain[window] >= 7) + return 1; + + /* even though there is no scalefactor for sfb12 + * subblock gain affects upper frequencies too, that's why + * we have to go up to SBMAX_s + */ + cod_info->subblock_gain[window]++; + j = gfc->scalefac_band.l[cod_info->sfb_lmax]; + for (sfb = cod_info->sfb_lmax + window; sfb < cod_info->sfbmax; sfb += 3) { + FLOAT amp; + int const width = cod_info->width[sfb]; + int s = scalefac[sfb]; + assert(s >= 0); + s = s - (4 >> cod_info->scalefac_scale); + if (s >= 0) { + scalefac[sfb] = s; + j += width * 3; + continue; + } + + scalefac[sfb] = 0; + { + int const gain = 210 + (s << (cod_info->scalefac_scale + 1)); + amp = IPOW20(gain); + } + j += width * (window + 1); + for (l = -width; l < 0; l++) { + xrpow[j + l] *= amp; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + j += width * (3 - window - 1); + } + + { + FLOAT const amp = IPOW20(202); + j += cod_info->width[sfb] * (window + 1); + for (l = -cod_info->width[sfb]; l < 0; l++) { + xrpow[j + l] *= amp; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + } + } + return 0; +} + + + +/******************************************************************** + * + * balance_noise() + * + * Takehiro Tominaga /date?? + * Robert Hegemann 2000-09-06: made a function of it + * + * amplifies scalefactor bands, + * - if all are already amplified returns 0 + * - if some bands are amplified too much: + * * try to increase scalefac_scale + * * if already scalefac_scale was set + * try on short blocks to increase subblock gain + * + ********************************************************************/ +inline static int +balance_noise(lame_internal_flags * gfc, + gr_info * const cod_info, FLOAT const *distort, FLOAT xrpow[576], int bRefine) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int status; + + amp_scalefac_bands(gfc, cod_info, distort, xrpow, bRefine); + + /* check to make sure we have not amplified too much + * loop_break returns 0 if there is an unamplified scalefac + * scale_bitcount returns 0 if no scalefactors are too large + */ + + status = loop_break(cod_info); + + if (status) + return 0; /* all bands amplified */ + + /* not all scalefactors have been amplified. so these + * scalefacs are possibly valid. encode them: + */ + status = scale_bitcount(gfc, cod_info); + + if (!status) + return 1; /* amplified some bands not exceeding limits */ + + /* some scalefactors are too large. + * lets try setting scalefac_scale=1 + */ + if (cfg->noise_shaping > 1) { + memset(&gfc->sv_qnt.pseudohalf[0], 0, sizeof(gfc->sv_qnt.pseudohalf)); + if (!cod_info->scalefac_scale) { + inc_scalefac_scale(cod_info, xrpow); + status = 0; + } + else { + if (cod_info->block_type == SHORT_TYPE && cfg->subblock_gain > 0) { + status = inc_subblock_gain(gfc, cod_info, xrpow) + || loop_break(cod_info); + } + } + } + + if (!status) { + status = scale_bitcount(gfc, cod_info); + } + return !status; +} + + + +/************************************************************************ + * + * outer_loop () + * + * Function: The outer iteration loop controls the masking conditions + * of all scalefactorbands. It computes the best scalefac and + * global gain. This module calls the inner iteration loop + * + * mt 5/99 completely rewritten to allow for bit reservoir control, + * mid/side channels with L/R or mid/side masking thresholds, + * and chooses best quantization instead of last quantization when + * no distortion free quantization can be found. + * + * added VBR support mt 5/99 + * + * some code shuffle rh 9/00 + ************************************************************************/ + +static int +outer_loop(lame_internal_flags * gfc, gr_info * const cod_info, const FLOAT * const l3_xmin, /* allowed distortion */ + FLOAT xrpow[576], /* coloured magnitudes of spectral */ + const int ch, const int targ_bits) +{ /* maximum allowed bits */ + SessionConfig_t const *const cfg = &gfc->cfg; + gr_info cod_info_w; + FLOAT save_xrpow[576]; + FLOAT distort[SFBMAX]; + calc_noise_result best_noise_info; + int huff_bits; + int better; + int age; + calc_noise_data prev_noise; + int best_part2_3_length = 9999999; + int bEndOfSearch = 0; + int bRefine = 0; + int best_ggain_pass1 = 0; + + (void) bin_search_StepSize(gfc, cod_info, targ_bits, ch, xrpow); + + if (!cfg->noise_shaping) + /* fast mode, no noise shaping, we are ready */ + return 100; /* default noise_info.over_count */ + + memset(&prev_noise, 0, sizeof(calc_noise_data)); + + + /* compute the distortion in this quantization */ + /* coefficients and thresholds both l/r (or both mid/side) */ + (void) calc_noise(cod_info, l3_xmin, distort, &best_noise_info, &prev_noise); + best_noise_info.bits = cod_info->part2_3_length; + + cod_info_w = *cod_info; + age = 0; + /* if (cfg->vbr == vbr_rh || cfg->vbr == vbr_mtrh) */ + memcpy(save_xrpow, xrpow, sizeof(FLOAT) * 576); + + while (!bEndOfSearch) { + /* BEGIN MAIN LOOP */ + do { + calc_noise_result noise_info; + int search_limit; + int maxggain = 255; + + /* When quantization with no distorted bands is found, + * allow up to X new unsuccesful tries in serial. This + * gives us more possibilities for different quant_compare modes. + * Much more than 3 makes not a big difference, it is only slower. + */ + + if (gfc->sv_qnt.substep_shaping & 2) { + search_limit = 20; + } + else { + search_limit = 3; + } + + + + /* Check if the last scalefactor band is distorted. + * in VBR mode we can't get rid of the distortion, so quit now + * and VBR mode will try again with more bits. + * (makes a 10% speed increase, the files I tested were + * binary identical, 2000/05/20 Robert Hegemann) + * distort[] > 1 means noise > allowed noise + */ + if (gfc->sv_qnt.sfb21_extra) { + if (distort[cod_info_w.sfbmax] > 1.0) + break; + if (cod_info_w.block_type == SHORT_TYPE + && (distort[cod_info_w.sfbmax + 1] > 1.0 + || distort[cod_info_w.sfbmax + 2] > 1.0)) + break; + } + + /* try a new scalefactor conbination on cod_info_w */ + if (balance_noise(gfc, &cod_info_w, distort, xrpow, bRefine) == 0) + break; + if (cod_info_w.scalefac_scale) + maxggain = 254; + + /* inner_loop starts with the initial quantization step computed above + * and slowly increases until the bits < huff_bits. + * Thus it is important not to start with too large of an inital + * quantization step. Too small is ok, but inner_loop will take longer + */ + huff_bits = targ_bits - cod_info_w.part2_length; + if (huff_bits <= 0) + break; + + /* increase quantizer stepsize until needed bits are below maximum + */ + while ((cod_info_w.part2_3_length + = count_bits(gfc, xrpow, &cod_info_w, &prev_noise)) > huff_bits + && cod_info_w.global_gain <= maxggain) + cod_info_w.global_gain++; + + if (cod_info_w.global_gain > maxggain) + break; + + if (best_noise_info.over_count == 0) { + + while ((cod_info_w.part2_3_length + = count_bits(gfc, xrpow, &cod_info_w, &prev_noise)) > best_part2_3_length + && cod_info_w.global_gain <= maxggain) + cod_info_w.global_gain++; + + if (cod_info_w.global_gain > maxggain) + break; + } + + /* compute the distortion in this quantization */ + (void) calc_noise(&cod_info_w, l3_xmin, distort, &noise_info, &prev_noise); + noise_info.bits = cod_info_w.part2_3_length; + + /* check if this quantization is better + * than our saved quantization */ + if (cod_info->block_type != SHORT_TYPE) /* NORM, START or STOP type */ + better = cfg->quant_comp; + else + better = cfg->quant_comp_short; + + + better = quant_compare(better, &best_noise_info, &noise_info, &cod_info_w, distort); + + + /* save data so we can restore this quantization later */ + if (better) { + best_part2_3_length = cod_info->part2_3_length; + best_noise_info = noise_info; + *cod_info = cod_info_w; + age = 0; + /* save data so we can restore this quantization later */ + /*if (cfg->vbr == vbr_rh || cfg->vbr == vbr_mtrh) */ { + /* store for later reuse */ + memcpy(save_xrpow, xrpow, sizeof(FLOAT) * 576); + } + } + else { + /* early stop? */ + if (cfg->full_outer_loop == 0) { + if (++age > search_limit && best_noise_info.over_count == 0) + break; + if ((cfg->noise_shaping_amp == 3) && bRefine && age > 30) + break; + if ((cfg->noise_shaping_amp == 3) && bRefine && + (cod_info_w.global_gain - best_ggain_pass1) > 15) + break; + } + } + } + while ((cod_info_w.global_gain + cod_info_w.scalefac_scale) < 255); + + if (cfg->noise_shaping_amp == 3) { + if (!bRefine) { + /* refine search */ + cod_info_w = *cod_info; + memcpy(xrpow, save_xrpow, sizeof(FLOAT) * 576); + age = 0; + best_ggain_pass1 = cod_info_w.global_gain; + + bRefine = 1; + } + else { + /* search already refined, stop */ + bEndOfSearch = 1; + } + + } + else { + bEndOfSearch = 1; + } + } + + assert((cod_info->global_gain + cod_info->scalefac_scale) <= 255); + /* finish up + */ + if (cfg->vbr == vbr_rh || cfg->vbr == vbr_mtrh || cfg->vbr == vbr_mt) + /* restore for reuse on next try */ + memcpy(xrpow, save_xrpow, sizeof(FLOAT) * 576); + /* do the 'substep shaping' + */ + else if (gfc->sv_qnt.substep_shaping & 1) + trancate_smallspectrums(gfc, cod_info, l3_xmin, xrpow); + + return best_noise_info.over_count; +} + + + + + +/************************************************************************ + * + * iteration_finish_one() + * + * Robert Hegemann 2000-09-06 + * + * update reservoir status after FINAL quantization/bitrate + * + ************************************************************************/ + +static void +iteration_finish_one(lame_internal_flags * gfc, int gr, int ch) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + III_side_info_t *const l3_side = &gfc->l3_side; + gr_info *const cod_info = &l3_side->tt[gr][ch]; + + /* try some better scalefac storage + */ + best_scalefac_store(gfc, gr, ch, l3_side); + + /* best huffman_divide may save some bits too + */ + if (cfg->use_best_huffman == 1) + best_huffman_divide(gfc, cod_info); + + /* update reservoir status after FINAL quantization/bitrate + */ + ResvAdjust(gfc, cod_info); +} + + + +/********************************************************************* + * + * VBR_encode_granule() + * + * 2000-09-04 Robert Hegemann + * + *********************************************************************/ + +static void +VBR_encode_granule(lame_internal_flags * gfc, gr_info * const cod_info, const FLOAT * const l3_xmin, /* allowed distortion of the scalefactor */ + FLOAT xrpow[576], /* coloured magnitudes of spectral values */ + const int ch, int min_bits, int max_bits) +{ + gr_info bst_cod_info; + FLOAT bst_xrpow[576]; + int const Max_bits = max_bits; + int real_bits = max_bits + 1; + int this_bits = (max_bits + min_bits) / 2; + int dbits, over, found = 0; + int const sfb21_extra = gfc->sv_qnt.sfb21_extra; + + assert(Max_bits <= MAX_BITS_PER_CHANNEL); + memset(bst_cod_info.l3_enc, 0, sizeof(bst_cod_info.l3_enc)); + + /* search within round about 40 bits of optimal + */ + do { + assert(this_bits >= min_bits); + assert(this_bits <= max_bits); + assert(min_bits <= max_bits); + + if (this_bits > Max_bits - 42) + gfc->sv_qnt.sfb21_extra = 0; + else + gfc->sv_qnt.sfb21_extra = sfb21_extra; + + over = outer_loop(gfc, cod_info, l3_xmin, xrpow, ch, this_bits); + + /* is quantization as good as we are looking for ? + * in this case: is no scalefactor band distorted? + */ + if (over <= 0) { + found = 1; + /* now we know it can be done with "real_bits" + * and maybe we can skip some iterations + */ + real_bits = cod_info->part2_3_length; + + /* store best quantization so far + */ + bst_cod_info = *cod_info; + memcpy(bst_xrpow, xrpow, sizeof(FLOAT) * 576); + + /* try with fewer bits + */ + max_bits = real_bits - 32; + dbits = max_bits - min_bits; + this_bits = (max_bits + min_bits) / 2; + } + else { + /* try with more bits + */ + min_bits = this_bits + 32; + dbits = max_bits - min_bits; + this_bits = (max_bits + min_bits) / 2; + + if (found) { + found = 2; + /* start again with best quantization so far + */ + *cod_info = bst_cod_info; + memcpy(xrpow, bst_xrpow, sizeof(FLOAT) * 576); + } + } + } while (dbits > 12); + + gfc->sv_qnt.sfb21_extra = sfb21_extra; + + /* found=0 => nothing found, use last one + * found=1 => we just found the best and left the loop + * found=2 => we restored a good one and have now l3_enc to restore too + */ + if (found == 2) { + memcpy(cod_info->l3_enc, bst_cod_info.l3_enc, sizeof(int) * 576); + } + assert(cod_info->part2_3_length <= Max_bits); + +} + + + +/************************************************************************ + * + * get_framebits() + * + * Robert Hegemann 2000-09-05 + * + * calculates + * * how many bits are available for analog silent granules + * * how many bits to use for the lowest allowed bitrate + * * how many bits each bitrate would provide + * + ************************************************************************/ + +static void +get_framebits(lame_internal_flags * gfc, int frameBits[15]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + int bitsPerFrame, i; + + /* always use at least this many bits per granule per channel + * unless we detect analog silence, see below + */ + eov->bitrate_index = cfg->vbr_min_bitrate_index; + bitsPerFrame = getframebits(gfc); + + /* bits for analog silence + */ + eov->bitrate_index = 1; + bitsPerFrame = getframebits(gfc); + + for (i = 1; i <= cfg->vbr_max_bitrate_index; i++) { + eov->bitrate_index = i; + frameBits[i] = ResvFrameBegin(gfc, &bitsPerFrame); + } +} + + + +/********************************************************************* + * + * VBR_prepare() + * + * 2000-09-04 Robert Hegemann + * + * * converts LR to MS coding when necessary + * * calculates allowed/adjusted quantization noise amounts + * * detects analog silent frames + * + * some remarks: + * - lower masking depending on Quality setting + * - quality control together with adjusted ATH MDCT scaling + * on lower quality setting allocate more noise from + * ATH masking, and on higher quality setting allocate + * less noise from ATH masking. + * - experiments show that going more than 2dB over GPSYCHO's + * limits ends up in very annoying artefacts + * + *********************************************************************/ + +/* RH: this one needs to be overhauled sometime */ + +static int +VBR_old_prepare(lame_internal_flags * gfc, + const FLOAT pe[2][2], FLOAT const ms_ener_ratio[2], + const III_psy_ratio ratio[2][2], + FLOAT l3_xmin[2][2][SFBMAX], + int frameBits[16], int min_bits[2][2], int max_bits[2][2], int bands[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + + FLOAT masking_lower_db, adjust = 0.0; + int gr, ch; + int analog_silence = 1; + int avg, mxb, bits = 0; + + eov->bitrate_index = cfg->vbr_max_bitrate_index; + avg = ResvFrameBegin(gfc, &avg) / cfg->mode_gr; + + get_framebits(gfc, frameBits); + + for (gr = 0; gr < cfg->mode_gr; gr++) { + mxb = on_pe(gfc, pe, max_bits[gr], avg, gr, 0); + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + reduce_side(max_bits[gr], ms_ener_ratio[gr], avg, mxb); + } + for (ch = 0; ch < cfg->channels_out; ++ch) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type */ + adjust = 1.28 / (1 + exp(3.5 - pe[gr][ch] / 300.)) - 0.05; + masking_lower_db = gfc->sv_qnt.mask_adjust - adjust; + } + else { + adjust = 2.56 / (1 + exp(3.5 - pe[gr][ch] / 300.)) - 0.14; + masking_lower_db = gfc->sv_qnt.mask_adjust_short - adjust; + } + gfc->sv_qnt.masking_lower = pow(10.0, masking_lower_db * 0.1); + + init_outer_loop(gfc, cod_info); + bands[gr][ch] = calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin[gr][ch]); + if (bands[gr][ch]) + analog_silence = 0; + + min_bits[gr][ch] = 126; + + bits += max_bits[gr][ch]; + } + } + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + if (bits > frameBits[cfg->vbr_max_bitrate_index] && bits > 0) { + max_bits[gr][ch] *= frameBits[cfg->vbr_max_bitrate_index]; + max_bits[gr][ch] /= bits; + } + if (min_bits[gr][ch] > max_bits[gr][ch]) + min_bits[gr][ch] = max_bits[gr][ch]; + + } /* for ch */ + } /* for gr */ + + return analog_silence; +} + +static void +bitpressure_strategy(lame_internal_flags const *gfc, + FLOAT l3_xmin[2][2][SFBMAX], const int min_bits[2][2], int max_bits[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int gr, ch, sfb; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const gi = &gfc->l3_side.tt[gr][ch]; + FLOAT *pxmin = l3_xmin[gr][ch]; + for (sfb = 0; sfb < gi->psy_lmax; sfb++) + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_l / SBMAX_l; + + if (gi->block_type == SHORT_TYPE) { + for (sfb = gi->sfb_smin; sfb < SBMAX_s; sfb++) { + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_s / SBMAX_s; + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_s / SBMAX_s; + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_s / SBMAX_s; + } + } + max_bits[gr][ch] = Max(min_bits[gr][ch], 0.9 * max_bits[gr][ch]); + } + } +} + +/************************************************************************ + * + * VBR_iteration_loop() + * + * tries to find out how many bits are needed for each granule and channel + * to get an acceptable quantization. An appropriate bitrate will then be + * choosed for quantization. rh 8/99 + * + * Robert Hegemann 2000-09-06 rewrite + * + ************************************************************************/ + +void +VBR_old_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + FLOAT l3_xmin[2][2][SFBMAX]; + + FLOAT xrpow[576]; + int bands[2][2]; + int frameBits[15]; + int used_bits; + int bits; + int min_bits[2][2], max_bits[2][2]; + int mean_bits; + int ch, gr, analog_silence; + III_side_info_t *const l3_side = &gfc->l3_side; + + analog_silence = VBR_old_prepare(gfc, pe, ms_ener_ratio, ratio, + l3_xmin, frameBits, min_bits, max_bits, bands); + + /*---------------------------------*/ + for (;;) { + + /* quantize granules with lowest possible number of bits + */ + + used_bits = 0; + + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + int ret; + gr_info *const cod_info = &l3_side->tt[gr][ch]; + + /* init_outer_loop sets up cod_info, scalefac and xrpow + */ + ret = init_xrpow(gfc, cod_info, xrpow); + if (ret == 0 || max_bits[gr][ch] == 0) { + /* xr contains no energy + * l3_enc, our encoding data, will be quantized to zero + */ + continue; /* with next channel */ + } + + VBR_encode_granule(gfc, cod_info, l3_xmin[gr][ch], xrpow, + ch, min_bits[gr][ch], max_bits[gr][ch]); + + /* do the 'substep shaping' + */ + if (gfc->sv_qnt.substep_shaping & 1) { + trancate_smallspectrums(gfc, &l3_side->tt[gr][ch], l3_xmin[gr][ch], xrpow); + } + + ret = cod_info->part2_3_length + cod_info->part2_length; + used_bits += ret; + } /* for ch */ + } /* for gr */ + + /* find lowest bitrate able to hold used bits + */ + if (analog_silence && !cfg->enforce_min_bitrate) + /* we detected analog silence and the user did not specify + * any hard framesize limit, so start with smallest possible frame + */ + eov->bitrate_index = 1; + else + eov->bitrate_index = cfg->vbr_min_bitrate_index; + + for (; eov->bitrate_index < cfg->vbr_max_bitrate_index; eov->bitrate_index++) { + if (used_bits <= frameBits[eov->bitrate_index]) + break; + } + bits = ResvFrameBegin(gfc, &mean_bits); + + if (used_bits <= bits) + break; + + bitpressure_strategy(gfc, l3_xmin, (const int (*)[2])min_bits, max_bits); + + } /* breaks adjusted */ + /*--------------------------------------*/ + + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + iteration_finish_one(gfc, gr, ch); + } /* for ch */ + } /* for gr */ + ResvFrameEnd(gfc, mean_bits); +} + + + +static int +VBR_new_prepare(lame_internal_flags * gfc, + const FLOAT pe[2][2], const III_psy_ratio ratio[2][2], + FLOAT l3_xmin[2][2][SFBMAX], int frameBits[16], int max_bits[2][2], + int* max_resv) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + + int gr, ch; + int analog_silence = 1; + int avg, bits = 0; + int maximum_framebits; + + if (!cfg->free_format) { + eov->bitrate_index = cfg->vbr_max_bitrate_index; + (void) ResvFrameBegin(gfc, &avg); + *max_resv = gfc->sv_enc.ResvMax; + + get_framebits(gfc, frameBits); + maximum_framebits = frameBits[cfg->vbr_max_bitrate_index]; + } + else { + eov->bitrate_index = 0; + maximum_framebits = ResvFrameBegin(gfc, &avg); + frameBits[0] = maximum_framebits; + *max_resv = gfc->sv_enc.ResvMax; + } + + for (gr = 0; gr < cfg->mode_gr; gr++) { + (void) on_pe(gfc, pe, max_bits[gr], avg, gr, 0); + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + } + for (ch = 0; ch < cfg->channels_out; ++ch) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + + gfc->sv_qnt.masking_lower = pow(10.0, gfc->sv_qnt.mask_adjust * 0.1); + + init_outer_loop(gfc, cod_info); + if (0 != calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin[gr][ch])) + analog_silence = 0; + + bits += max_bits[gr][ch]; + } + } + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + if (bits > maximum_framebits && bits > 0) { + max_bits[gr][ch] *= maximum_framebits; + max_bits[gr][ch] /= bits; + } + + } /* for ch */ + } /* for gr */ + if (analog_silence) { + *max_resv = 0; + } + return analog_silence; +} + + + +void +VBR_new_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + FLOAT l3_xmin[2][2][SFBMAX]; + + FLOAT xrpow[2][2][576]; + int frameBits[15]; + int used_bits; + int max_bits[2][2]; + int ch, gr, analog_silence, pad; + III_side_info_t *const l3_side = &gfc->l3_side; + + const FLOAT (*const_l3_xmin)[2][SFBMAX] = (const FLOAT (*)[2][SFBMAX])l3_xmin; + const FLOAT (*const_xrpow)[2][576] = (const FLOAT (*)[2][576])xrpow; + const int (*const_max_bits)[2] = (const int (*)[2])max_bits; + + (void) ms_ener_ratio; /* not used */ + + memset(xrpow, 0, sizeof(xrpow)); + + analog_silence = VBR_new_prepare(gfc, pe, ratio, l3_xmin, frameBits, max_bits, &pad); + + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const cod_info = &l3_side->tt[gr][ch]; + + /* init_outer_loop sets up cod_info, scalefac and xrpow + */ + if (0 == init_xrpow(gfc, cod_info, xrpow[gr][ch])) { + max_bits[gr][ch] = 0; /* silent granule needs no bits */ + } + } /* for ch */ + } /* for gr */ + + /* quantize granules with lowest possible number of bits + */ + + used_bits = VBR_encode_frame(gfc, const_xrpow, const_l3_xmin, const_max_bits); + + if (!cfg->free_format) { + int i, j; + + /* find lowest bitrate able to hold used bits + */ + if (analog_silence && !cfg->enforce_min_bitrate) { + /* we detected analog silence and the user did not specify + * any hard framesize limit, so start with smallest possible frame + */ + i = 1; + } + else { + i = cfg->vbr_min_bitrate_index; + } + + for (; i < cfg->vbr_max_bitrate_index; i++) { + if (used_bits <= frameBits[i]) + break; + } + if (i > cfg->vbr_max_bitrate_index) { + i = cfg->vbr_max_bitrate_index; + } + if (pad > 0) { + for (j = cfg->vbr_max_bitrate_index; j > i; --j) { + int const unused = frameBits[j] - used_bits; + if (unused <= pad) + break; + } + eov->bitrate_index = j; + } + else { + eov->bitrate_index = i; + } + } + else { +#if 0 + static int mmm = 0; + int fff = getFramesize_kbps(gfc, used_bits); + int hhh = getFramesize_kbps(gfc, MAX_BITS_PER_GRANULE * cfg->mode_gr); + if (mmm < fff) + mmm = fff; + printf("demand=%3d kbps max=%3d kbps limit=%3d kbps\n", fff, mmm, hhh); +#endif + eov->bitrate_index = 0; + } + if (used_bits <= frameBits[eov->bitrate_index]) { + /* update Reservoire status */ + int mean_bits, fullframebits; + fullframebits = ResvFrameBegin(gfc, &mean_bits); + assert(used_bits <= fullframebits); + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const cod_info = &l3_side->tt[gr][ch]; + ResvAdjust(gfc, cod_info); + } + } + ResvFrameEnd(gfc, mean_bits); + } + else { + /* SHOULD NOT HAPPEN INTERNAL ERROR + */ + ERRORF(gfc, "INTERNAL ERROR IN VBR NEW CODE, please send bug report\n"); + exit(-1); + } +} + + + + + +/******************************************************************** + * + * calc_target_bits() + * + * calculates target bits for ABR encoding + * + * mt 2000/05/31 + * + ********************************************************************/ + +static void +calc_target_bits(lame_internal_flags * gfc, + const FLOAT pe[2][2], + FLOAT const ms_ener_ratio[2], + int targ_bits[2][2], int *analog_silence_bits, int *max_frame_bits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + III_side_info_t const *const l3_side = &gfc->l3_side; + FLOAT res_factor; + int gr, ch, totbits, mean_bits; + int framesize = 576 * cfg->mode_gr; + + eov->bitrate_index = cfg->vbr_max_bitrate_index; + *max_frame_bits = ResvFrameBegin(gfc, &mean_bits); + + eov->bitrate_index = 1; + mean_bits = getframebits(gfc) - cfg->sideinfo_len * 8; + *analog_silence_bits = mean_bits / (cfg->mode_gr * cfg->channels_out); + + mean_bits = cfg->vbr_avg_bitrate_kbps * framesize * 1000; + if (gfc->sv_qnt.substep_shaping & 1) + mean_bits *= 1.09; + mean_bits /= cfg->samplerate_out; + mean_bits -= cfg->sideinfo_len * 8; + mean_bits /= (cfg->mode_gr * cfg->channels_out); + + /* + res_factor is the percentage of the target bitrate that should + be used on average. the remaining bits are added to the + bitreservoir and used for difficult to encode frames. + + Since we are tracking the average bitrate, we should adjust + res_factor "on the fly", increasing it if the average bitrate + is greater than the requested bitrate, and decreasing it + otherwise. Reasonable ranges are from .9 to 1.0 + + Until we get the above suggestion working, we use the following + tuning: + compression ratio res_factor + 5.5 (256kbps) 1.0 no need for bitreservoir + 11 (128kbps) .93 7% held for reservoir + + with linear interpolation for other values. + + */ + res_factor = .93 + .07 * (11.0 - cfg->compression_ratio) / (11.0 - 5.5); + if (res_factor < .90) + res_factor = .90; + if (res_factor > 1.00) + res_factor = 1.00; + + for (gr = 0; gr < cfg->mode_gr; gr++) { + int sum = 0; + for (ch = 0; ch < cfg->channels_out; ch++) { + targ_bits[gr][ch] = res_factor * mean_bits; + + if (pe[gr][ch] > 700) { + int add_bits = (pe[gr][ch] - 700) / 1.4; + + gr_info const *const cod_info = &l3_side->tt[gr][ch]; + targ_bits[gr][ch] = res_factor * mean_bits; + + /* short blocks use a little extra, no matter what the pe */ + if (cod_info->block_type == SHORT_TYPE) { + if (add_bits < mean_bits / 2) + add_bits = mean_bits / 2; + } + /* at most increase bits by 1.5*average */ + if (add_bits > mean_bits * 3 / 2) + add_bits = mean_bits * 3 / 2; + else if (add_bits < 0) + add_bits = 0; + + targ_bits[gr][ch] += add_bits; + } + if (targ_bits[gr][ch] > MAX_BITS_PER_CHANNEL) { + targ_bits[gr][ch] = MAX_BITS_PER_CHANNEL; + } + sum += targ_bits[gr][ch]; + } /* for ch */ + if (sum > MAX_BITS_PER_GRANULE) { + for (ch = 0; ch < cfg->channels_out; ++ch) { + targ_bits[gr][ch] *= MAX_BITS_PER_GRANULE; + targ_bits[gr][ch] /= sum; + } + } + } /* for gr */ + + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) + for (gr = 0; gr < cfg->mode_gr; gr++) { + reduce_side(targ_bits[gr], ms_ener_ratio[gr], mean_bits * cfg->channels_out, + MAX_BITS_PER_GRANULE); + } + + /* sum target bits + */ + totbits = 0; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + if (targ_bits[gr][ch] > MAX_BITS_PER_CHANNEL) + targ_bits[gr][ch] = MAX_BITS_PER_CHANNEL; + totbits += targ_bits[gr][ch]; + } + } + + /* repartion target bits if needed + */ + if (totbits > *max_frame_bits && totbits > 0) { + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + targ_bits[gr][ch] *= *max_frame_bits; + targ_bits[gr][ch] /= totbits; + } + } + } +} + + + + + + +/******************************************************************** + * + * ABR_iteration_loop() + * + * encode a frame with a disired average bitrate + * + * mt 2000/05/31 + * + ********************************************************************/ + +void +ABR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + FLOAT l3_xmin[SFBMAX]; + FLOAT xrpow[576]; + int targ_bits[2][2]; + int mean_bits, max_frame_bits; + int ch, gr, ath_over; + int analog_silence_bits; + gr_info *cod_info; + III_side_info_t *const l3_side = &gfc->l3_side; + + mean_bits = 0; + + calc_target_bits(gfc, pe, ms_ener_ratio, targ_bits, &analog_silence_bits, &max_frame_bits); + + /* encode granules + */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + } + for (ch = 0; ch < cfg->channels_out; ch++) { + FLOAT adjust, masking_lower_db; + cod_info = &l3_side->tt[gr][ch]; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type */ + /* adjust = 1.28/(1+exp(3.5-pe[gr][ch]/300.))-0.05; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust - adjust; + } + else { + /* adjust = 2.56/(1+exp(3.5-pe[gr][ch]/300.))-0.14; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust_short - adjust; + } + gfc->sv_qnt.masking_lower = pow(10.0, masking_lower_db * 0.1); + + + /* cod_info, scalefac and xrpow get initialized in init_outer_loop + */ + init_outer_loop(gfc, cod_info); + if (init_xrpow(gfc, cod_info, xrpow)) { + /* xr contains energy we will have to encode + * calculate the masking abilities + * find some good quantization in outer_loop + */ + ath_over = calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin); + if (0 == ath_over) /* analog silence */ + targ_bits[gr][ch] = analog_silence_bits; + + (void) outer_loop(gfc, cod_info, l3_xmin, xrpow, ch, targ_bits[gr][ch]); + } + iteration_finish_one(gfc, gr, ch); + } /* ch */ + } /* gr */ + + /* find a bitrate which can refill the resevoir to positive size. + */ + for (eov->bitrate_index = cfg->vbr_min_bitrate_index; + eov->bitrate_index <= cfg->vbr_max_bitrate_index; eov->bitrate_index++) { + if (ResvFrameBegin(gfc, &mean_bits) >= 0) + break; + } + assert(eov->bitrate_index <= cfg->vbr_max_bitrate_index); + + ResvFrameEnd(gfc, mean_bits); +} + + + + + + +/************************************************************************ + * + * CBR_iteration_loop() + * + * author/date?? + * + * encodes one frame of MP3 data with constant bitrate + * + ************************************************************************/ + +void +CBR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + FLOAT l3_xmin[SFBMAX]; + FLOAT xrpow[576]; + int targ_bits[2]; + int mean_bits, max_bits; + int gr, ch; + III_side_info_t *const l3_side = &gfc->l3_side; + gr_info *cod_info; + + (void) ResvFrameBegin(gfc, &mean_bits); + + /* quantize! */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + + /* calculate needed bits + */ + max_bits = on_pe(gfc, pe, targ_bits, mean_bits, gr, gr); + + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + reduce_side(targ_bits, ms_ener_ratio[gr], mean_bits, max_bits); + } + + for (ch = 0; ch < cfg->channels_out; ch++) { + FLOAT adjust, masking_lower_db; + cod_info = &l3_side->tt[gr][ch]; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type */ + /* adjust = 1.28/(1+exp(3.5-pe[gr][ch]/300.))-0.05; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust - adjust; + } + else { + /* adjust = 2.56/(1+exp(3.5-pe[gr][ch]/300.))-0.14; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust_short - adjust; + } + gfc->sv_qnt.masking_lower = pow(10.0, masking_lower_db * 0.1); + + /* init_outer_loop sets up cod_info, scalefac and xrpow + */ + init_outer_loop(gfc, cod_info); + if (init_xrpow(gfc, cod_info, xrpow)) { + /* xr contains energy we will have to encode + * calculate the masking abilities + * find some good quantization in outer_loop + */ + (void) calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin); + (void) outer_loop(gfc, cod_info, l3_xmin, xrpow, ch, targ_bits[ch]); + } + + iteration_finish_one(gfc, gr, ch); + assert(cod_info->part2_3_length <= MAX_BITS_PER_CHANNEL); + assert(cod_info->part2_3_length <= targ_bits[ch]); + } /* for ch */ + } /* for gr */ + + ResvFrameEnd(gfc, mean_bits); +} diff --git a/pkg/lame/clame/quantize.h b/pkg/lame/clame/quantize.h new file mode 100644 index 0000000..56edcc7 --- /dev/null +++ b/pkg/lame/clame/quantize.h @@ -0,0 +1,38 @@ +/* + * MP3 quantization + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_QUANTIZE_H +#define LAME_QUANTIZE_H + +void CBR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + +void VBR_old_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + +void VBR_new_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + +void ABR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + + +#endif /* LAME_QUANTIZE_H */ diff --git a/pkg/lame/clame/quantize_pvt.c b/pkg/lame/clame/quantize_pvt.c new file mode 100644 index 0000000..d8d6447 --- /dev/null +++ b/pkg/lame/clame/quantize_pvt.c @@ -0,0 +1,1074 @@ +/* + * quantize_pvt source file + * + * Copyright (c) 1999-2002 Takehiro Tominaga + * Copyright (c) 2000-2012 Robert Hegemann + * Copyright (c) 2001 Naoki Shibata + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: quantize_pvt.c,v 1.175 2017/09/06 15:07:30 robert Exp $ */ +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "quantize_pvt.h" +#include "reservoir.h" +#include "lame-analysis.h" +#include + + +#define NSATHSCALE 100 /* Assuming dynamic range=96dB, this value should be 92 */ + +/* + The following table is used to implement the scalefactor + partitioning for MPEG2 as described in section + 2.4.3.2 of the IS. The indexing corresponds to the + way the tables are presented in the IS: + + [table_number][row_in_table][column of nr_of_sfb] +*/ +const int nr_of_sfb_block[6][3][4] = { + { + {6, 5, 5, 5}, + {9, 9, 9, 9}, + {6, 9, 9, 9} + }, + { + {6, 5, 7, 3}, + {9, 9, 12, 6}, + {6, 9, 12, 6} + }, + { + {11, 10, 0, 0}, + {18, 18, 0, 0}, + {15, 18, 0, 0} + }, + { + {7, 7, 7, 0}, + {12, 12, 12, 0}, + {6, 15, 12, 0} + }, + { + {6, 6, 6, 3}, + {12, 9, 9, 6}, + {6, 12, 9, 6} + }, + { + {8, 8, 5, 0}, + {15, 12, 9, 0}, + {6, 18, 9, 0} + } +}; + + +/* Table B.6: layer3 preemphasis */ +const int pretab[SBMAX_l] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 +}; + +/* + Here are MPEG1 Table B.8 and MPEG2 Table B.1 + -- Layer III scalefactor bands. + Index into this using a method such as: + idx = fr_ps->header->sampling_frequency + + (fr_ps->header->version * 3) +*/ + + +const scalefac_struct sfBandIndex[9] = { + { /* Table B.2.b: 22.05 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.2.c: 24 kHz */ /* docs: 332. mpg123(broken): 330 */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464, + 540, 576}, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.2.a: 16 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.8.b: 44.1 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, + 576}, + {0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.8.c: 48 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, + 576}, + {0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.8.a: 32 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, + 576}, + {0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* MPEG-2.5 11.025 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0 / 3, 12 / 3, 24 / 3, 36 / 3, 54 / 3, 78 / 3, 108 / 3, 144 / 3, 186 / 3, 240 / 3, 312 / 3, + 402 / 3, 522 / 3, 576 / 3} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* MPEG-2.5 12 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0 / 3, 12 / 3, 24 / 3, 36 / 3, 54 / 3, 78 / 3, 108 / 3, 144 / 3, 186 / 3, 240 / 3, 312 / 3, + 402 / 3, 522 / 3, 576 / 3} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* MPEG-2.5 8 kHz */ + {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, + 572, 574, 576}, + {0 / 3, 24 / 3, 48 / 3, 72 / 3, 108 / 3, 156 / 3, 216 / 3, 288 / 3, 372 / 3, 480 / 3, 486 / 3, + 492 / 3, 498 / 3, 576 / 3} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + } +}; + + +/* FIXME: move global variables in some struct */ + +FLOAT pow20[Q_MAX + Q_MAX2 + 1]; +FLOAT ipow20[Q_MAX]; +FLOAT pow43[PRECALC_SIZE]; +/* initialized in first call to iteration_init */ +#ifdef TAKEHIRO_IEEE754_HACK +FLOAT adj43asm[PRECALC_SIZE]; +#else +FLOAT adj43[PRECALC_SIZE]; +#endif + +/* +compute the ATH for each scalefactor band +cd range: 0..96db + +Input: 3.3kHz signal 32767 amplitude (3.3kHz is where ATH is smallest = -5db) +longblocks: sfb=12 en0/bw=-11db max_en0 = 1.3db +shortblocks: sfb=5 -9db 0db + +Input: 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 (repeated) +longblocks: amp=1 sfb=12 en0/bw=-103 db max_en0 = -92db + amp=32767 sfb=12 -12 db -1.4db + +Input: 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 (repeated) +shortblocks: amp=1 sfb=5 en0/bw= -99 -86 + amp=32767 sfb=5 -9 db 4db + + +MAX energy of largest wave at 3.3kHz = 1db +AVE energy of largest wave at 3.3kHz = -11db +Let's take AVE: -11db = maximum signal in sfb=12. +Dynamic range of CD: 96db. Therefor energy of smallest audible wave +in sfb=12 = -11 - 96 = -107db = ATH at 3.3kHz. + +ATH formula for this wave: -5db. To adjust to LAME scaling, we need +ATH = ATH_formula - 103 (db) +ATH = ATH * 2.5e-10 (ener) + +*/ + +static FLOAT +ATHmdct(SessionConfig_t const *cfg, FLOAT f) +{ + FLOAT ath; + + ath = ATHformula(cfg, f); + + if (cfg->ATHfixpoint > 0) { + ath -= cfg->ATHfixpoint; + } + else { + ath -= NSATHSCALE; + } + ath += cfg->ATH_offset_db; + + /* modify the MDCT scaling for the ATH and convert to energy */ + ath = powf(10.0f, ath * 0.1f); + return ath; +} + +static void +compute_ath(lame_internal_flags const* gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + FLOAT *const ATH_l = gfc->ATH->l; + FLOAT *const ATH_psfb21 = gfc->ATH->psfb21; + FLOAT *const ATH_s = gfc->ATH->s; + FLOAT *const ATH_psfb12 = gfc->ATH->psfb12; + int sfb, i, start, end; + FLOAT ATH_f; + FLOAT const samp_freq = cfg->samplerate_out; + + for (sfb = 0; sfb < SBMAX_l; sfb++) { + start = gfc->scalefac_band.l[sfb]; + end = gfc->scalefac_band.l[sfb + 1]; + ATH_l[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 576); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_l[sfb] = Min(ATH_l[sfb], ATH_f); + } + } + + for (sfb = 0; sfb < PSFB21; sfb++) { + start = gfc->scalefac_band.psfb21[sfb]; + end = gfc->scalefac_band.psfb21[sfb + 1]; + ATH_psfb21[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 576); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_psfb21[sfb] = Min(ATH_psfb21[sfb], ATH_f); + } + } + + for (sfb = 0; sfb < SBMAX_s; sfb++) { + start = gfc->scalefac_band.s[sfb]; + end = gfc->scalefac_band.s[sfb + 1]; + ATH_s[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 192); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_s[sfb] = Min(ATH_s[sfb], ATH_f); + } + ATH_s[sfb] *= (gfc->scalefac_band.s[sfb + 1] - gfc->scalefac_band.s[sfb]); + } + + for (sfb = 0; sfb < PSFB12; sfb++) { + start = gfc->scalefac_band.psfb12[sfb]; + end = gfc->scalefac_band.psfb12[sfb + 1]; + ATH_psfb12[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 192); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_psfb12[sfb] = Min(ATH_psfb12[sfb], ATH_f); + } + /*not sure about the following */ + ATH_psfb12[sfb] *= (gfc->scalefac_band.s[13] - gfc->scalefac_band.s[12]); + } + + + /* no-ATH mode: + * reduce ATH to -200 dB + */ + + if (cfg->noATH) { + for (sfb = 0; sfb < SBMAX_l; sfb++) { + ATH_l[sfb] = 1E-20; + } + for (sfb = 0; sfb < PSFB21; sfb++) { + ATH_psfb21[sfb] = 1E-20; + } + for (sfb = 0; sfb < SBMAX_s; sfb++) { + ATH_s[sfb] = 1E-20; + } + for (sfb = 0; sfb < PSFB12; sfb++) { + ATH_psfb12[sfb] = 1E-20; + } + } + + /* work in progress, don't rely on it too much + */ + gfc->ATH->floor = 10. * log10(ATHmdct(cfg, -1.)); + + /* + { FLOAT g=10000, t=1e30, x; + for ( f = 100; f < 10000; f++ ) { + x = ATHmdct( cfg, f ); + if ( t > x ) t = x, g = f; + } + printf("min=%g\n", g); + } */ +} + + +static float const payload_long[2][4] = +{ {-0.000f, -0.000f, -0.000f, +0.000f} +, {-0.500f, -0.250f, -0.025f, +0.500f} +}; +static float const payload_short[2][4] = +{ {-0.000f, -0.000f, -0.000f, +0.000f} +, {-2.000f, -1.000f, -0.050f, +0.500f} +}; + +/************************************************************************/ +/* initialization for iteration_loop */ +/************************************************************************/ +void +iteration_init(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + III_side_info_t *const l3_side = &gfc->l3_side; + FLOAT adjust, db; + int i, sel; + + if (gfc->iteration_init_init == 0) { + gfc->iteration_init_init = 1; + + l3_side->main_data_begin = 0; + compute_ath(gfc); + + pow43[0] = 0.0; + for (i = 1; i < PRECALC_SIZE; i++) + pow43[i] = pow((FLOAT) i, 4.0 / 3.0); + +#ifdef TAKEHIRO_IEEE754_HACK + adj43asm[0] = 0.0; + for (i = 1; i < PRECALC_SIZE; i++) + adj43asm[i] = i - 0.5 - pow(0.5 * (pow43[i - 1] + pow43[i]), 0.75); +#else + for (i = 0; i < PRECALC_SIZE - 1; i++) + adj43[i] = (i + 1) - pow(0.5 * (pow43[i] + pow43[i + 1]), 0.75); + adj43[i] = 0.5; +#endif + for (i = 0; i < Q_MAX; i++) + ipow20[i] = pow(2.0, (double) (i - 210) * -0.1875); + for (i = 0; i <= Q_MAX + Q_MAX2; i++) + pow20[i] = pow(2.0, (double) (i - 210 - Q_MAX2) * 0.25); + + huffman_init(gfc); + init_xrpow_core_init(gfc); + + sel = 1;/* RH: all modes like vbr-new (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh) ? 1 : 0;*/ + + /* long */ + db = cfg->adjust_bass_db + payload_long[sel][0]; + adjust = powf(10.f, db * 0.1f); + for (i = 0; i <= 6; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + db = cfg->adjust_alto_db + payload_long[sel][1]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 13; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + db = cfg->adjust_treble_db + payload_long[sel][2]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 20; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + db = cfg->adjust_sfb21_db + payload_long[sel][3]; + adjust = powf(10.f, db * 0.1f); + for (; i < SBMAX_l; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + + /* short */ + db = cfg->adjust_bass_db + payload_short[sel][0]; + adjust = powf(10.f, db * 0.1f); + for (i = 0; i <= 2; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + db = cfg->adjust_alto_db + payload_short[sel][1]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 6; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + db = cfg->adjust_treble_db + payload_short[sel][2]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 11; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + db = cfg->adjust_sfb21_db + payload_short[sel][3]; + adjust = powf(10.f, db * 0.1f); + for (; i < SBMAX_s; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + } +} + + + + + +/************************************************************************ + * allocate bits among 2 channels based on PE + * mt 6/99 + * bugfixes rh 8/01: often allocated more than the allowed 4095 bits + ************************************************************************/ +int +on_pe(lame_internal_flags * gfc, const FLOAT pe[][2], int targ_bits[2], int mean_bits, int gr, int cbr) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int extra_bits = 0, tbits, bits; + int add_bits[2] = {0, 0}; + int max_bits; /* maximum allowed bits for this granule */ + int ch; + + /* allocate targ_bits for granule */ + ResvMaxBits(gfc, mean_bits, &tbits, &extra_bits, cbr); + max_bits = tbits + extra_bits; + if (max_bits > MAX_BITS_PER_GRANULE) /* hard limit per granule */ + max_bits = MAX_BITS_PER_GRANULE; + + for (bits = 0, ch = 0; ch < cfg->channels_out; ++ch) { + /****************************************************************** + * allocate bits for each channel + ******************************************************************/ + targ_bits[ch] = Min(MAX_BITS_PER_CHANNEL, tbits / cfg->channels_out); + + add_bits[ch] = targ_bits[ch] * pe[gr][ch] / 700.0 - targ_bits[ch]; + + /* at most increase bits by 1.5*average */ + if (add_bits[ch] > mean_bits * 3 / 4) + add_bits[ch] = mean_bits * 3 / 4; + if (add_bits[ch] < 0) + add_bits[ch] = 0; + + if (add_bits[ch] + targ_bits[ch] > MAX_BITS_PER_CHANNEL) + add_bits[ch] = Max(0, MAX_BITS_PER_CHANNEL - targ_bits[ch]); + + bits += add_bits[ch]; + } + if (bits > extra_bits && bits > 0) { + for (ch = 0; ch < cfg->channels_out; ++ch) { + add_bits[ch] = extra_bits * add_bits[ch] / bits; + } + } + + for (ch = 0; ch < cfg->channels_out; ++ch) { + targ_bits[ch] += add_bits[ch]; + extra_bits -= add_bits[ch]; + } + + for (bits = 0, ch = 0; ch < cfg->channels_out; ++ch) { + bits += targ_bits[ch]; + } + if (bits > MAX_BITS_PER_GRANULE) { + int sum = 0; + for (ch = 0; ch < cfg->channels_out; ++ch) { + targ_bits[ch] *= MAX_BITS_PER_GRANULE; + targ_bits[ch] /= bits; + sum += targ_bits[ch]; + } + assert(sum <= MAX_BITS_PER_GRANULE); + } + + return max_bits; +} + + + + +void +reduce_side(int targ_bits[2], FLOAT ms_ener_ratio, int mean_bits, int max_bits) +{ + int move_bits; + FLOAT fac; + + assert(max_bits <= MAX_BITS_PER_GRANULE); + assert(targ_bits[0] + targ_bits[1] <= MAX_BITS_PER_GRANULE); + + /* ms_ener_ratio = 0: allocate 66/33 mid/side fac=.33 + * ms_ener_ratio =.5: allocate 50/50 mid/side fac= 0 */ + /* 75/25 split is fac=.5 */ + /* float fac = .50*(.5-ms_ener_ratio[gr])/.5; */ + fac = .33 * (.5 - ms_ener_ratio) / .5; + if (fac < 0) + fac = 0; + if (fac > .5) + fac = .5; + + /* number of bits to move from side channel to mid channel */ + /* move_bits = fac*targ_bits[1]; */ + move_bits = fac * .5 * (targ_bits[0] + targ_bits[1]); + + if (move_bits > MAX_BITS_PER_CHANNEL - targ_bits[0]) { + move_bits = MAX_BITS_PER_CHANNEL - targ_bits[0]; + } + if (move_bits < 0) + move_bits = 0; + + if (targ_bits[1] >= 125) { + /* dont reduce side channel below 125 bits */ + if (targ_bits[1] - move_bits > 125) { + + /* if mid channel already has 2x more than average, dont bother */ + /* mean_bits = bits per granule (for both channels) */ + if (targ_bits[0] < mean_bits) + targ_bits[0] += move_bits; + targ_bits[1] -= move_bits; + } + else { + targ_bits[0] += targ_bits[1] - 125; + targ_bits[1] = 125; + } + } + + move_bits = targ_bits[0] + targ_bits[1]; + if (move_bits > max_bits) { + targ_bits[0] = (max_bits * targ_bits[0]) / move_bits; + targ_bits[1] = (max_bits * targ_bits[1]) / move_bits; + } + assert(targ_bits[0] <= MAX_BITS_PER_CHANNEL); + assert(targ_bits[1] <= MAX_BITS_PER_CHANNEL); + assert(targ_bits[0] + targ_bits[1] <= MAX_BITS_PER_GRANULE); +} + + +/** + * Robert Hegemann 2001-04-27: + * this adjusts the ATH, keeping the original noise floor + * affects the higher frequencies more than the lower ones + */ + +FLOAT +athAdjust(FLOAT a, FLOAT x, FLOAT athFloor, float ATHfixpoint) +{ + /* work in progress + */ + FLOAT const o = 90.30873362f; + FLOAT const p = (ATHfixpoint < 1.f) ? 94.82444863f : ATHfixpoint; + FLOAT u = FAST_LOG10_X(x, 10.0f); + FLOAT const v = a * a; + FLOAT w = 0.0f; + u -= athFloor; /* undo scaling */ + if (v > 1E-20f) + w = 1.f + FAST_LOG10_X(v, 10.0f / o); + if (w < 0) + w = 0.f; + u *= w; + u += athFloor + o - p; /* redo scaling */ + + return powf(10.f, 0.1f * u); +} + + + +/*************************************************************************/ +/* calc_xmin */ +/*************************************************************************/ + +/* + Calculate the allowed distortion for each scalefactor band, + as determined by the psychoacoustic model. + xmin(sb) = ratio(sb) * en(sb) / bw(sb) + + returns number of sfb's with energy > ATH +*/ + +int +calc_xmin(lame_internal_flags const *gfc, + III_psy_ratio const *const ratio, gr_info * const cod_info, FLOAT * pxmin) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfb, gsfb, j = 0, ath_over = 0, k; + ATH_t const *const ATH = gfc->ATH; + const FLOAT *const xr = cod_info->xr; + int max_nonzero; + + for (gsfb = 0; gsfb < cod_info->psy_lmax; gsfb++) { + FLOAT en0, xmin; + FLOAT rh1, rh2, rh3; + int width, l; + + xmin = athAdjust(ATH->adjust_factor, ATH->l[gsfb], ATH->floor, cfg->ATHfixpoint); + xmin *= gfc->sv_qnt.longfact[gsfb]; + + width = cod_info->width[gsfb]; + rh1 = xmin / width; +#ifdef DBL_EPSILON + rh2 = DBL_EPSILON; +#else + rh2 = 2.2204460492503131e-016; +#endif + en0 = 0.0; + for (l = 0; l < width; ++l) { + FLOAT const xa = xr[j++]; + FLOAT const x2 = xa * xa; + en0 += x2; + rh2 += (x2 < rh1) ? x2 : rh1; + } + if (en0 > xmin) + ath_over++; + + if (en0 < xmin) { + rh3 = en0; + } + else if (rh2 < xmin) { + rh3 = xmin; + } + else { + rh3 = rh2; + } + xmin = rh3; + { + FLOAT const e = ratio->en.l[gsfb]; + if (e > 1e-12f) { + FLOAT x; + x = en0 * ratio->thm.l[gsfb] / e; + x *= gfc->sv_qnt.longfact[gsfb]; + if (xmin < x) + xmin = x; + } + } + xmin = Max(xmin, DBL_EPSILON); + cod_info->energy_above_cutoff[gsfb] = (en0 > xmin+1e-14f) ? 1 : 0; + *pxmin++ = xmin; + } /* end of long block loop */ + + + + + /*use this function to determine the highest non-zero coeff */ + max_nonzero = 0; + for (k = 575; k > 0; --k) { + if (fabs(xr[k]) > 1e-12f) { + max_nonzero = k; + break; + } + } + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type, but not SHORT */ + max_nonzero |= 1; /* only odd numbers */ + } + else { + max_nonzero /= 6; /* 3 short blocks */ + max_nonzero *= 6; + max_nonzero += 5; + } + + if (gfc->sv_qnt.sfb21_extra == 0 && cfg->samplerate_out < 44000) { + int const sfb_l = (cfg->samplerate_out <= 8000) ? 17 : 21; + int const sfb_s = (cfg->samplerate_out <= 8000) ? 9 : 12; + int limit = 575; + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type, but not SHORT */ + limit = gfc->scalefac_band.l[sfb_l]-1; + } + else { + limit = 3*gfc->scalefac_band.s[sfb_s]-1; + } + if (max_nonzero > limit) { + max_nonzero = limit; + } + } + cod_info->max_nonzero_coeff = max_nonzero; + + + + for (sfb = cod_info->sfb_smin; gsfb < cod_info->psymax; sfb++, gsfb += 3) { + int width, b, l; + FLOAT tmpATH; + + tmpATH = athAdjust(ATH->adjust_factor, ATH->s[sfb], ATH->floor, cfg->ATHfixpoint); + tmpATH *= gfc->sv_qnt.shortfact[sfb]; + + width = cod_info->width[gsfb]; + for (b = 0; b < 3; b++) { + FLOAT en0 = 0.0, xmin = tmpATH; + FLOAT rh1, rh2, rh3; + + rh1 = tmpATH / width; +#ifdef DBL_EPSILON + rh2 = DBL_EPSILON; +#else + rh2 = 2.2204460492503131e-016; +#endif + for (l = 0; l < width; ++l) { + FLOAT const xa = xr[j++]; + FLOAT const x2 = xa * xa; + en0 += x2; + rh2 += (x2 < rh1) ? x2 : rh1; + } + if (en0 > tmpATH) + ath_over++; + + if (en0 < tmpATH) { + rh3 = en0; + } + else if (rh2 < tmpATH) { + rh3 = tmpATH; + } + else { + rh3 = rh2; + } + xmin = rh3; + { + FLOAT const e = ratio->en.s[sfb][b]; + if (e > 1e-12f) { + FLOAT x; + x = en0 * ratio->thm.s[sfb][b] / e; + x *= gfc->sv_qnt.shortfact[sfb]; + if (xmin < x) + xmin = x; + } + } + xmin = Max(xmin, DBL_EPSILON); + cod_info->energy_above_cutoff[gsfb+b] = (en0 > xmin+1e-14f) ? 1 : 0; + *pxmin++ = xmin; + } /* b */ + if (cfg->use_temporal_masking_effect) { + if (pxmin[-3] > pxmin[-3 + 1]) + pxmin[-3 + 1] += (pxmin[-3] - pxmin[-3 + 1]) * gfc->cd_psy->decay; + if (pxmin[-3 + 1] > pxmin[-3 + 2]) + pxmin[-3 + 2] += (pxmin[-3 + 1] - pxmin[-3 + 2]) * gfc->cd_psy->decay; + } + } /* end of short block sfb loop */ + + return ath_over; +} + + +static FLOAT +calc_noise_core_c(const gr_info * const cod_info, int *startline, int l, FLOAT step) +{ + FLOAT noise = 0; + int j = *startline; + const int *const ix = cod_info->l3_enc; + + if (j > cod_info->count1) { + while (l--) { + FLOAT temp; + temp = cod_info->xr[j]; + j++; + noise += temp * temp; + temp = cod_info->xr[j]; + j++; + noise += temp * temp; + } + } + else if (j > cod_info->big_values) { + FLOAT ix01[2]; + ix01[0] = 0; + ix01[1] = step; + while (l--) { + FLOAT temp; + temp = fabs(cod_info->xr[j]) - ix01[ix[j]]; + j++; + noise += temp * temp; + temp = fabs(cod_info->xr[j]) - ix01[ix[j]]; + j++; + noise += temp * temp; + } + } + else { + while (l--) { + FLOAT temp; + temp = fabs(cod_info->xr[j]) - pow43[ix[j]] * step; + j++; + noise += temp * temp; + temp = fabs(cod_info->xr[j]) - pow43[ix[j]] * step; + j++; + noise += temp * temp; + } + } + + *startline = j; + return noise; +} + + +/*************************************************************************/ +/* calc_noise */ +/*************************************************************************/ + +/* -oo dB => -1.00 */ +/* - 6 dB => -0.97 */ +/* - 3 dB => -0.80 */ +/* - 2 dB => -0.64 */ +/* - 1 dB => -0.38 */ +/* 0 dB => 0.00 */ +/* + 1 dB => +0.49 */ +/* + 2 dB => +1.06 */ +/* + 3 dB => +1.68 */ +/* + 6 dB => +3.69 */ +/* +10 dB => +6.45 */ + +int +calc_noise(gr_info const *const cod_info, + FLOAT const *l3_xmin, + FLOAT * distort, calc_noise_result * const res, calc_noise_data * prev_noise) +{ + int sfb, l, over = 0; + FLOAT over_noise_db = 0; + FLOAT tot_noise_db = 0; /* 0 dB relative to masking */ + FLOAT max_noise = -20.0; /* -200 dB relative to masking */ + int j = 0; + const int *scalefac = cod_info->scalefac; + + res->over_SSD = 0; + + + for (sfb = 0; sfb < cod_info->psymax; sfb++) { + int const s = + cod_info->global_gain - (((*scalefac++) + (cod_info->preflag ? pretab[sfb] : 0)) + << (cod_info->scalefac_scale + 1)) + - cod_info->subblock_gain[cod_info->window[sfb]] * 8; + FLOAT const r_l3_xmin = 1.f / *l3_xmin++; + FLOAT distort_ = 0.0f; + FLOAT noise = 0.0f; + + if (prev_noise && (prev_noise->step[sfb] == s)) { + + /* use previously computed values */ + j += cod_info->width[sfb]; + distort_ = r_l3_xmin * prev_noise->noise[sfb]; + + noise = prev_noise->noise_log[sfb]; + + } + else { + FLOAT const step = POW20(s); + l = cod_info->width[sfb] >> 1; + + if ((j + cod_info->width[sfb]) > cod_info->max_nonzero_coeff) { + int usefullsize; + usefullsize = cod_info->max_nonzero_coeff - j + 1; + + if (usefullsize > 0) + l = usefullsize >> 1; + else + l = 0; + } + + noise = calc_noise_core_c(cod_info, &j, l, step); + + + if (prev_noise) { + /* save noise values */ + prev_noise->step[sfb] = s; + prev_noise->noise[sfb] = noise; + } + + distort_ = r_l3_xmin * noise; + + /* multiplying here is adding in dB, but can overflow */ + noise = FAST_LOG10(Max(distort_, 1E-20f)); + + if (prev_noise) { + /* save noise values */ + prev_noise->noise_log[sfb] = noise; + } + } + *distort++ = distort_; + + if (prev_noise) { + /* save noise values */ + prev_noise->global_gain = cod_info->global_gain;; + } + + + /*tot_noise *= Max(noise, 1E-20); */ + tot_noise_db += noise; + + if (noise > 0.0) { + int tmp; + + tmp = Max((int) (noise * 10 + .5), 1); + res->over_SSD += tmp * tmp; + + over++; + /* multiplying here is adding in dB -but can overflow */ + /*over_noise *= noise; */ + over_noise_db += noise; + } + max_noise = Max(max_noise, noise); + + } + + res->over_count = over; + res->tot_noise = tot_noise_db; + res->over_noise = over_noise_db; + res->max_noise = max_noise; + + return over; +} + + + + + + + + +/************************************************************************ + * + * set_pinfo() + * + * updates plotting data + * + * Mark Taylor 2000-??-?? + * + * Robert Hegemann: moved noise/distortion calc into it + * + ************************************************************************/ + +static void +set_pinfo(lame_internal_flags const *gfc, + gr_info * const cod_info, const III_psy_ratio * const ratio, const int gr, const int ch) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfb, sfb2; + int j, i, l, start, end, bw; + FLOAT en0, en1; + FLOAT const ifqstep = (cod_info->scalefac_scale == 0) ? .5 : 1.0; + int const *const scalefac = cod_info->scalefac; + + FLOAT l3_xmin[SFBMAX], xfsf[SFBMAX]; + calc_noise_result noise; + + (void) calc_xmin(gfc, ratio, cod_info, l3_xmin); + (void) calc_noise(cod_info, l3_xmin, xfsf, &noise, 0); + + j = 0; + sfb2 = cod_info->sfb_lmax; + if (cod_info->block_type != SHORT_TYPE && !cod_info->mixed_block_flag) + sfb2 = 22; + for (sfb = 0; sfb < sfb2; sfb++) { + start = gfc->scalefac_band.l[sfb]; + end = gfc->scalefac_band.l[sfb + 1]; + bw = end - start; + for (en0 = 0.0; j < end; j++) + en0 += cod_info->xr[j] * cod_info->xr[j]; + en0 /= bw; + /* convert to MDCT units */ + en1 = 1e15; /* scaling so it shows up on FFT plot */ + gfc->pinfo->en[gr][ch][sfb] = en1 * en0; + gfc->pinfo->xfsf[gr][ch][sfb] = en1 * l3_xmin[sfb] * xfsf[sfb] / bw; + + if (ratio->en.l[sfb] > 0 && !cfg->ATHonly) + en0 = en0 / ratio->en.l[sfb]; + else + en0 = 0.0; + + gfc->pinfo->thr[gr][ch][sfb] = en1 * Max(en0 * ratio->thm.l[sfb], gfc->ATH->l[sfb]); + + /* there is no scalefactor bands >= SBPSY_l */ + gfc->pinfo->LAMEsfb[gr][ch][sfb] = 0; + if (cod_info->preflag && sfb >= 11) + gfc->pinfo->LAMEsfb[gr][ch][sfb] = -ifqstep * pretab[sfb]; + + if (sfb < SBPSY_l) { + assert(scalefac[sfb] >= 0); /* scfsi should be decoded by caller side */ + gfc->pinfo->LAMEsfb[gr][ch][sfb] -= ifqstep * scalefac[sfb]; + } + } /* for sfb */ + + if (cod_info->block_type == SHORT_TYPE) { + sfb2 = sfb; + for (sfb = cod_info->sfb_smin; sfb < SBMAX_s; sfb++) { + start = gfc->scalefac_band.s[sfb]; + end = gfc->scalefac_band.s[sfb + 1]; + bw = end - start; + for (i = 0; i < 3; i++) { + for (en0 = 0.0, l = start; l < end; l++) { + en0 += cod_info->xr[j] * cod_info->xr[j]; + j++; + } + en0 = Max(en0 / bw, 1e-20); + /* convert to MDCT units */ + en1 = 1e15; /* scaling so it shows up on FFT plot */ + + gfc->pinfo->en_s[gr][ch][3 * sfb + i] = en1 * en0; + gfc->pinfo->xfsf_s[gr][ch][3 * sfb + i] = en1 * l3_xmin[sfb2] * xfsf[sfb2] / bw; + if (ratio->en.s[sfb][i] > 0) + en0 = en0 / ratio->en.s[sfb][i]; + else + en0 = 0.0; + if (cfg->ATHonly || cfg->ATHshort) + en0 = 0; + + gfc->pinfo->thr_s[gr][ch][3 * sfb + i] = + en1 * Max(en0 * ratio->thm.s[sfb][i], gfc->ATH->s[sfb]); + + /* there is no scalefactor bands >= SBPSY_s */ + gfc->pinfo->LAMEsfb_s[gr][ch][3 * sfb + i] + = -2.0 * cod_info->subblock_gain[i]; + if (sfb < SBPSY_s) { + gfc->pinfo->LAMEsfb_s[gr][ch][3 * sfb + i] -= ifqstep * scalefac[sfb2]; + } + sfb2++; + } + } + } /* block type short */ + gfc->pinfo->LAMEqss[gr][ch] = cod_info->global_gain; + gfc->pinfo->LAMEmainbits[gr][ch] = cod_info->part2_3_length + cod_info->part2_length; + gfc->pinfo->LAMEsfbits[gr][ch] = cod_info->part2_length; + + gfc->pinfo->over[gr][ch] = noise.over_count; + gfc->pinfo->max_noise[gr][ch] = noise.max_noise * 10.0; + gfc->pinfo->over_noise[gr][ch] = noise.over_noise * 10.0; + gfc->pinfo->tot_noise[gr][ch] = noise.tot_noise * 10.0; + gfc->pinfo->over_SSD[gr][ch] = noise.over_SSD; +} + + +/************************************************************************ + * + * set_frame_pinfo() + * + * updates plotting data for a whole frame + * + * Robert Hegemann 2000-10-21 + * + ************************************************************************/ + +void +set_frame_pinfo(lame_internal_flags * gfc, const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int ch; + int gr; + + /* for every granule and channel patch l3_enc and set info + */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + int scalefac_sav[SFBMAX]; + memcpy(scalefac_sav, cod_info->scalefac, sizeof(scalefac_sav)); + + /* reconstruct the scalefactors in case SCFSI was used + */ + if (gr == 1) { + int sfb; + for (sfb = 0; sfb < cod_info->sfb_lmax; sfb++) { + if (cod_info->scalefac[sfb] < 0) /* scfsi */ + cod_info->scalefac[sfb] = gfc->l3_side.tt[0][ch].scalefac[sfb]; + } + } + + set_pinfo(gfc, cod_info, &ratio[gr][ch], gr, ch); + memcpy(cod_info->scalefac, scalefac_sav, sizeof(scalefac_sav)); + } /* for ch */ + } /* for gr */ +} diff --git a/pkg/lame/clame/quantize_pvt.h b/pkg/lame/clame/quantize_pvt.h new file mode 100644 index 0000000..b8333e7 --- /dev/null +++ b/pkg/lame/clame/quantize_pvt.h @@ -0,0 +1,128 @@ +/* + * quantize_pvt include file + * + * Copyright (c) 1999 Takehiro TOMINAGA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_QUANTIZE_PVT_H +#define LAME_QUANTIZE_PVT_H + +#define IXMAX_VAL 8206 /* ix always <= 8191+15. see count_bits() */ + +/* buggy Winamp decoder cannot handle values > 8191 */ +/* #define IXMAX_VAL 8191 */ + +#define PRECALC_SIZE (IXMAX_VAL+2) + + +extern const int nr_of_sfb_block[6][3][4]; +extern const int pretab[SBMAX_l]; +extern const int slen1_tab[16]; +extern const int slen2_tab[16]; + +extern const scalefac_struct sfBandIndex[9]; + +extern FLOAT pow43[PRECALC_SIZE]; +#ifdef TAKEHIRO_IEEE754_HACK +extern FLOAT adj43asm[PRECALC_SIZE]; +#else +extern FLOAT adj43[PRECALC_SIZE]; +#endif + +#define Q_MAX (256+1) +#define Q_MAX2 116 /* minimum possible number of + -cod_info->global_gain + + ((scalefac[] + (cod_info->preflag ? pretab[sfb] : 0)) + << (cod_info->scalefac_scale + 1)) + + cod_info->subblock_gain[cod_info->window[sfb]] * 8; + + for long block, 0+((15+3)<<2) = 18*4 = 72 + for short block, 0+(15<<2)+7*8 = 15*4+56 = 116 + */ + +extern FLOAT pow20[Q_MAX + Q_MAX2 + 1]; +extern FLOAT ipow20[Q_MAX]; + +typedef struct calc_noise_result_t { + FLOAT over_noise; /* sum of quantization noise > masking */ + FLOAT tot_noise; /* sum of all quantization noise */ + FLOAT max_noise; /* max quantization noise */ + int over_count; /* number of quantization noise > masking */ + int over_SSD; /* SSD-like cost of distorted bands */ + int bits; +} calc_noise_result; + + +/** +* allows re-use of previously +* computed noise values +*/ +typedef struct calc_noise_data_t { + int global_gain; + int sfb_count1; + int step[39]; + FLOAT noise[39]; + FLOAT noise_log[39]; +} calc_noise_data; + + +int on_pe(lame_internal_flags * gfc, const FLOAT pe[2][2], + int targ_bits[2], int mean_bits, int gr, int cbr); + +void reduce_side(int targ_bits[2], FLOAT ms_ener_ratio, int mean_bits, int max_bits); + + +void iteration_init(lame_internal_flags * gfc); + + +int calc_xmin(lame_internal_flags const *gfc, + III_psy_ratio const *const ratio, gr_info * const cod_info, FLOAT * l3_xmin); + +int calc_noise(const gr_info * const cod_info, + const FLOAT * l3_xmin, + FLOAT * distort, calc_noise_result * const res, calc_noise_data * prev_noise); + +void set_frame_pinfo(lame_internal_flags * gfc, const III_psy_ratio ratio[2][2]); + + + + +/* takehiro.c */ + +int count_bits(lame_internal_flags const *const gfc, const FLOAT * const xr, + gr_info * const cod_info, calc_noise_data * prev_noise); +int noquant_count_bits(lame_internal_flags const *const gfc, + gr_info * const cod_info, calc_noise_data * prev_noise); + + +void best_huffman_divide(const lame_internal_flags * const gfc, gr_info * const cod_info); + +void best_scalefac_store(const lame_internal_flags * gfc, const int gr, const int ch, + III_side_info_t * const l3_side); + +int scale_bitcount(const lame_internal_flags * gfc, gr_info * cod_info); + +void huffman_init(lame_internal_flags * const gfc); + +void init_xrpow_core_init(lame_internal_flags * const gfc); + +FLOAT athAdjust(FLOAT a, FLOAT x, FLOAT athFloor, float ATHfixpoint); + +#define LARGE_BITS 100000 + +#endif /* LAME_QUANTIZE_PVT_H */ diff --git a/pkg/lame/clame/reservoir.c b/pkg/lame/clame/reservoir.c new file mode 100644 index 0000000..4fdaa8d --- /dev/null +++ b/pkg/lame/clame/reservoir.c @@ -0,0 +1,293 @@ +/* + * bit reservoir source file + * + * Copyright (c) 1999-2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: reservoir.c,v 1.45 2011/05/07 16:05:17 rbrito Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "reservoir.h" + +#include "bitstream.h" +#include "lame-analysis.h" +#include "lame_global_flags.h" + + +/* + ResvFrameBegin: + Called (repeatedly) at the beginning of a frame. Updates the maximum + size of the reservoir, and checks to make sure main_data_begin + was set properly by the formatter +*/ + +/* + * Background information: + * + * This is the original text from the ISO standard. Because of + * sooo many bugs and irritations correcting comments are added + * in brackets []. A '^W' means you should remove the last word. + * + * 1) The following rule can be used to calculate the maximum + * number of bits used for one granule [^W frame]: + * At the highest possible bitrate of Layer III (320 kbps + * per stereo signal [^W^W^W], 48 kHz) the frames must be of + * [^W^W^W are designed to have] constant length, i.e. + * one buffer [^W^W the frame] length is: + * + * 320 kbps * 1152/48 kHz = 7680 bit = 960 byte + * + * This value is used as the maximum buffer per channel [^W^W] at + * lower bitrates [than 320 kbps]. At 64 kbps mono or 128 kbps + * stereo the main granule length is 64 kbps * 576/48 kHz = 768 bit + * [per granule and channel] at 48 kHz sampling frequency. + * This means that there is a maximum deviation (short time buffer + * [= reservoir]) of 7680 - 2*2*768 = 4608 bits is allowed at 64 kbps. + * The actual deviation is equal to the number of bytes [with the + * meaning of octets] denoted by the main_data_end offset pointer. + * The actual maximum deviation is (2^9-1)*8 bit = 4088 bits + * [for MPEG-1 and (2^8-1)*8 bit for MPEG-2, both are hard limits]. + * ... The xchange of buffer bits between the left and right channel + * is allowed without restrictions [exception: dual channel]. + * Because of the [constructed] constraint on the buffer size + * main_data_end is always set to 0 in the case of bit_rate_index==14, + * i.e. data rate 320 kbps per stereo signal [^W^W^W]. In this case + * all data are allocated between adjacent header [^W sync] words + * [, i.e. there is no buffering at all]. + */ + +int +ResvFrameBegin(lame_internal_flags * gfc, int *mean_bits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int fullFrameBits; + int resvLimit; + int maxmp3buf; + III_side_info_t *const l3_side = &gfc->l3_side; + int frameLength; + int meanBits; + + frameLength = getframebits(gfc); + meanBits = (frameLength - cfg->sideinfo_len * 8) / cfg->mode_gr; + +/* + * Meaning of the variables: + * resvLimit: (0, 8, ..., 8*255 (MPEG-2), 8*511 (MPEG-1)) + * Number of bits can be stored in previous frame(s) due to + * counter size constaints + * maxmp3buf: ( ??? ... 8*1951 (MPEG-1 and 2), 8*2047 (MPEG-2.5)) + * Number of bits allowed to encode one frame (you can take 8*511 bit + * from the bit reservoir and at most 8*1440 bit from the current + * frame (320 kbps, 32 kHz), so 8*1951 bit is the largest possible + * value for MPEG-1 and -2) + * + * maximum allowed granule/channel size times 4 = 8*2047 bits., + * so this is the absolute maximum supported by the format. + * + * + * fullFrameBits: maximum number of bits available for encoding + * the current frame. + * + * mean_bits: target number of bits per granule. + * + * frameLength: + * + * gfc->ResvMax: maximum allowed reservoir + * + * gfc->ResvSize: current reservoir size + * + * l3_side->resvDrain_pre: + * ancillary data to be added to previous frame: + * (only usefull in VBR modes if it is possible to have + * maxmp3buf < fullFrameBits)). Currently disabled, + * see #define NEW_DRAIN + * 2010-02-13: RH now enabled, it seems to be needed for CBR too, + * as there exists one example, where the FhG decoder + * can't decode a -b320 CBR file anymore. + * + * l3_side->resvDrain_post: + * ancillary data to be added to this frame: + * + */ + + /* main_data_begin has 9 bits in MPEG-1, 8 bits MPEG-2 */ + resvLimit = (8 * 256) * cfg->mode_gr - 8; + + /* maximum allowed frame size. dont use more than this number of + bits, even if the frame has the space for them: */ + maxmp3buf = cfg->buffer_constraint; + esv->ResvMax = maxmp3buf - frameLength; + if (esv->ResvMax > resvLimit) + esv->ResvMax = resvLimit; + if (esv->ResvMax < 0 || cfg->disable_reservoir) + esv->ResvMax = 0; + + fullFrameBits = meanBits * cfg->mode_gr + Min(esv->ResvSize, esv->ResvMax); + + if (fullFrameBits > maxmp3buf) + fullFrameBits = maxmp3buf; + + assert(0 == esv->ResvMax % 8); + assert(esv->ResvMax >= 0); + + l3_side->resvDrain_pre = 0; + + if (gfc->pinfo != NULL) { + gfc->pinfo->mean_bits = meanBits / 2; /* expected bits per channel per granule [is this also right for mono/stereo, MPEG-1/2 ?] */ + gfc->pinfo->resvsize = esv->ResvSize; + } + *mean_bits = meanBits; + return fullFrameBits; +} + + +/* + ResvMaxBits + returns targ_bits: target number of bits to use for 1 granule + extra_bits: amount extra available from reservoir + Mark Taylor 4/99 +*/ +void +ResvMaxBits(lame_internal_flags * gfc, int mean_bits, int *targ_bits, int *extra_bits, int cbr) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int add_bits, targBits, extraBits; + int ResvSize = esv->ResvSize, ResvMax = esv->ResvMax; + + /* conpensate the saved bits used in the 1st granule */ + if (cbr) + ResvSize += mean_bits; + + if (gfc->sv_qnt.substep_shaping & 1) + ResvMax *= 0.9; + + targBits = mean_bits; + + /* extra bits if the reservoir is almost full */ + if (ResvSize * 10 > ResvMax * 9) { + add_bits = ResvSize - (ResvMax * 9) / 10; + targBits += add_bits; + gfc->sv_qnt.substep_shaping |= 0x80; + } + else { + add_bits = 0; + gfc->sv_qnt.substep_shaping &= 0x7f; + /* build up reservoir. this builds the reservoir a little slower + * than FhG. It could simple be mean_bits/15, but this was rigged + * to always produce 100 (the old value) at 128kbs */ + /* *targ_bits -= (int) (mean_bits/15.2); */ + if (!cfg->disable_reservoir && !(gfc->sv_qnt.substep_shaping & 1)) + targBits -= .1 * mean_bits; + } + + + /* amount from the reservoir we are allowed to use. ISO says 6/10 */ + extraBits = (ResvSize < (esv->ResvMax * 6) / 10 ? ResvSize : (esv->ResvMax * 6) / 10); + extraBits -= add_bits; + + if (extraBits < 0) + extraBits = 0; + + *targ_bits = targBits; + *extra_bits = extraBits; +} + +/* + ResvAdjust: + Called after a granule's bit allocation. Readjusts the size of + the reservoir to reflect the granule's usage. +*/ +void +ResvAdjust(lame_internal_flags * gfc, gr_info const *gi) +{ + gfc->sv_enc.ResvSize -= gi->part2_3_length + gi->part2_length; +} + + +/* + ResvFrameEnd: + Called after all granules in a frame have been allocated. Makes sure + that the reservoir size is within limits, possibly by adding stuffing + bits. +*/ +void +ResvFrameEnd(lame_internal_flags * gfc, int mean_bits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + III_side_info_t *const l3_side = &gfc->l3_side; + int stuffingBits; + int over_bits; + + esv->ResvSize += mean_bits * cfg->mode_gr; + stuffingBits = 0; + l3_side->resvDrain_post = 0; + l3_side->resvDrain_pre = 0; + + /* we must be byte aligned */ + if ((over_bits = esv->ResvSize % 8) != 0) + stuffingBits += over_bits; + + + over_bits = (esv->ResvSize - stuffingBits) - esv->ResvMax; + if (over_bits > 0) { + assert(0 == over_bits % 8); + assert(over_bits >= 0); + stuffingBits += over_bits; + } + + + /* NOTE: enabling the NEW_DRAIN code fixes some problems with FhG decoder + shipped with MS Windows operating systems. Using this, it is even + possible to use Gabriel's lax buffer consideration again, which + assumes, any decoder should have a buffer large enough + for a 320 kbps frame at 32 kHz sample rate. + + old drain code: + lame -b320 BlackBird.wav ---> does not play with GraphEdit.exe using FhG decoder V1.5 Build 50 + + new drain code: + lame -b320 BlackBird.wav ---> plays fine with GraphEdit.exe using FhG decoder V1.5 Build 50 + + Robert Hegemann, 2010-02-13. + */ + /* drain as many bits as possible into previous frame ancillary data + * In particular, in VBR mode ResvMax may have changed, and we have + * to make sure main_data_begin does not create a reservoir bigger + * than ResvMax mt 4/00*/ + { + int mdb_bytes = Min(l3_side->main_data_begin * 8, stuffingBits) / 8; + l3_side->resvDrain_pre += 8 * mdb_bytes; + stuffingBits -= 8 * mdb_bytes; + esv->ResvSize -= 8 * mdb_bytes; + l3_side->main_data_begin -= mdb_bytes; + } + /* drain the rest into this frames ancillary data */ + l3_side->resvDrain_post += stuffingBits; + esv->ResvSize -= stuffingBits; +} diff --git a/pkg/lame/clame/reservoir.h b/pkg/lame/clame/reservoir.h new file mode 100644 index 0000000..7c58593 --- /dev/null +++ b/pkg/lame/clame/reservoir.h @@ -0,0 +1,31 @@ +/* + * bit reservoir include file + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_RESERVOIR_H +#define LAME_RESERVOIR_H + +int ResvFrameBegin(lame_internal_flags * gfc, int *mean_bits); +void ResvMaxBits(lame_internal_flags * gfc, int mean_bits, int *targ_bits, int *max_bits, + int cbr); +void ResvAdjust(lame_internal_flags * gfc, gr_info const *gi); +void ResvFrameEnd(lame_internal_flags * gfc, int mean_bits); + +#endif /* LAME_RESERVOIR_H */ diff --git a/pkg/lame/clame/set_get.c b/pkg/lame/clame/set_get.c new file mode 100644 index 0000000..f763900 --- /dev/null +++ b/pkg/lame/clame/set_get.c @@ -0,0 +1,2346 @@ +/* -*- mode: C; mode: fold -*- */ +/* + * set/get functions for lame_global_flags + * + * Copyright (c) 2001-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: set_get.c,v 1.104 2017/09/06 15:07:30 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "bitstream.h" /* because of compute_flushbits */ + +#include "set_get.h" +#include "lame_global_flags.h" + +/* + * input stream description + */ + + +/* number of samples */ +/* it's unlikely for this function to return an error */ +int +lame_set_num_samples(lame_global_flags * gfp, unsigned long num_samples) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 2^32-1 */ + gfp->num_samples = num_samples; + return 0; + } + return -1; +} + +unsigned long +lame_get_num_samples(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->num_samples; + } + return 0; +} + + +/* input samplerate */ +int +lame_set_in_samplerate(lame_global_flags * gfp, int in_samplerate) +{ + if (is_lame_global_flags_valid(gfp)) { + if (in_samplerate < 1) + return -1; + /* input sample rate in Hz, default = 44100 Hz */ + gfp->samplerate_in = in_samplerate; + return 0; + } + return -1; +} + +int +lame_get_in_samplerate(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->samplerate_in; + } + return 0; +} + + +/* number of channels in input stream */ +int +lame_set_num_channels(lame_global_flags * gfp, int num_channels) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 2 */ + if (2 < num_channels || 0 >= num_channels) { + return -1; /* we don't support more than 2 channels */ + } + gfp->num_channels = num_channels; + return 0; + } + return -1; +} + +int +lame_get_num_channels(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->num_channels; + } + return 0; +} + + +/* scale the input by this amount before encoding (not used for decoding) */ +int +lame_set_scale(lame_global_flags * gfp, float scale) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 */ + gfp->scale = scale; + return 0; + } + return -1; +} + +float +lame_get_scale(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->scale; + } + return 0; +} + + +/* scale the channel 0 (left) input by this amount before + encoding (not used for decoding) */ +int +lame_set_scale_left(lame_global_flags * gfp, float scale) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 */ + gfp->scale_left = scale; + return 0; + } + return -1; +} + +float +lame_get_scale_left(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->scale_left; + } + return 0; +} + + +/* scale the channel 1 (right) input by this amount before + encoding (not used for decoding) */ +int +lame_set_scale_right(lame_global_flags * gfp, float scale) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 */ + gfp->scale_right = scale; + return 0; + } + return -1; +} + +float +lame_get_scale_right(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->scale_right; + } + return 0; +} + + +/* output sample rate in Hz */ +int +lame_set_out_samplerate(lame_global_flags * gfp, int out_samplerate) +{ + if (is_lame_global_flags_valid(gfp)) { + /* + * default = 0: LAME picks best value based on the amount + * of compression + * MPEG only allows: + * MPEG1 32, 44.1, 48khz + * MPEG2 16, 22.05, 24 + * MPEG2.5 8, 11.025, 12 + * + * (not used by decoding routines) + */ + if (out_samplerate != 0) { + int v=0; + if (SmpFrqIndex(out_samplerate, &v) < 0) + return -1; + } + gfp->samplerate_out = out_samplerate; + return 0; + } + return -1; +} + +int +lame_get_out_samplerate(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->samplerate_out; + } + return 0; +} + + + + +/* + * general control parameters + */ + +/* collect data for an MP3 frame analzyer */ +int +lame_set_analysis(lame_global_flags * gfp, int analysis) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > analysis || 1 < analysis) + return -1; + gfp->analysis = analysis; + return 0; + } + return -1; +} + +int +lame_get_analysis(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->analysis && 1 >= gfp->analysis); + return gfp->analysis; + } + return 0; +} + + +/* write a Xing VBR header frame */ +int +lame_set_bWriteVbrTag(lame_global_flags * gfp, int bWriteVbrTag) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 (on) for VBR/ABR modes, 0 (off) for CBR mode */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > bWriteVbrTag || 1 < bWriteVbrTag) + return -1; + gfp->write_lame_tag = bWriteVbrTag; + return 0; + } + return -1; +} + +int +lame_get_bWriteVbrTag(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->write_lame_tag && 1 >= gfp->write_lame_tag); + return gfp->write_lame_tag; + } + return 0; +} + + + +/* decode only, use lame/mpglib to convert mp3 to wav */ +int +lame_set_decode_only(lame_global_flags * gfp, int decode_only) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > decode_only || 1 < decode_only) + return -1; + gfp->decode_only = decode_only; + return 0; + } + return -1; +} + +int +lame_get_decode_only(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->decode_only && 1 >= gfp->decode_only); + return gfp->decode_only; + } + return 0; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* 1=encode a Vorbis .ogg file. default=0 */ +/* DEPRECATED */ +int CDECL lame_set_ogg(lame_global_flags *, int); +int CDECL lame_get_ogg(const lame_global_flags *); +#else +#endif + +/* encode a Vorbis .ogg file */ +/* DEPRECATED */ +int +lame_set_ogg(lame_global_flags * gfp, int ogg) +{ + (void) gfp; + (void) ogg; + return -1; +} + +int +lame_get_ogg(const lame_global_flags * gfp) +{ + (void) gfp; + return 0; +} + + +/* + * Internal algorithm selection. + * True quality is determined by the bitrate but this variable will effect + * quality by selecting expensive or cheap algorithms. + * quality=0..9. 0=best (very slow). 9=worst. + * recommended: 3 near-best quality, not too slow + * 5 good quality, fast + * 7 ok quality, really fast + */ +int +lame_set_quality(lame_global_flags * gfp, int quality) +{ + if (is_lame_global_flags_valid(gfp)) { + if (quality < 0) { + gfp->quality = 0; + } + else if (quality > 9) { + gfp->quality = 9; + } + else { + gfp->quality = quality; + } + return 0; + } + return -1; +} + +int +lame_get_quality(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->quality; + } + return 0; +} + + +/* mode = STEREO, JOINT_STEREO, DUAL_CHANNEL (not supported), MONO */ +int +lame_set_mode(lame_global_flags * gfp, MPEG_mode mode) +{ + if (is_lame_global_flags_valid(gfp)) { + int mpg_mode = mode; + /* default: lame chooses based on compression ratio and input channels */ + if (mpg_mode < 0 || MAX_INDICATOR <= mpg_mode) + return -1; /* Unknown MPEG mode! */ + gfp->mode = mode; + return 0; + } + return -1; +} + +MPEG_mode +lame_get_mode(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(gfp->mode < MAX_INDICATOR); + return gfp->mode; + } + return NOT_SET; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* + mode_automs. Use a M/S mode with a switching threshold based on + compression ratio + DEPRECATED +*/ +int CDECL lame_set_mode_automs(lame_global_flags *, int); +int CDECL lame_get_mode_automs(const lame_global_flags *); +#else +#endif + +/* Us a M/S mode with a switching threshold based on compression ratio */ +/* DEPRECATED */ +int +lame_set_mode_automs(lame_global_flags * gfp, int mode_automs) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > mode_automs || 1 < mode_automs) + return -1; + lame_set_mode(gfp, JOINT_STEREO); + return 0; + } + return -1; +} + +int +lame_get_mode_automs(const lame_global_flags * gfp) +{ + (void) gfp; + return 1; +} + + +/* + * Force M/S for all frames. For testing only. + * Requires mode = 1. + */ +int +lame_set_force_ms(lame_global_flags * gfp, int force_ms) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > force_ms || 1 < force_ms) + return -1; + gfp->force_ms = force_ms; + return 0; + } + return -1; +} + +int +lame_get_force_ms(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->force_ms && 1 >= gfp->force_ms); + return gfp->force_ms; + } + return 0; +} + + +/* Use free_format. */ +int +lame_set_free_format(lame_global_flags * gfp, int free_format) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > free_format || 1 < free_format) + return -1; + gfp->free_format = free_format; + return 0; + } + return -1; +} + +int +lame_get_free_format(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->free_format && 1 >= gfp->free_format); + return gfp->free_format; + } + return 0; +} + + + +/* Perform ReplayGain analysis */ +int +lame_set_findReplayGain(lame_global_flags * gfp, int findReplayGain) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > findReplayGain || 1 < findReplayGain) + return -1; + gfp->findReplayGain = findReplayGain; + return 0; + } + return -1; +} + +int +lame_get_findReplayGain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->findReplayGain && 1 >= gfp->findReplayGain); + return gfp->findReplayGain; + } + return 0; +} + + +/* Decode on the fly. Find the peak sample. If ReplayGain analysis is + enabled then perform it on the decoded data. */ +int +lame_set_decode_on_the_fly(lame_global_flags * gfp, int decode_on_the_fly) +{ + if (is_lame_global_flags_valid(gfp)) { +#ifndef DECODE_ON_THE_FLY + return -1; +#else + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > decode_on_the_fly || 1 < decode_on_the_fly) + return -1; + + gfp->decode_on_the_fly = decode_on_the_fly; + + return 0; +#endif + } + return -1; +} + +int +lame_get_decode_on_the_fly(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->decode_on_the_fly && 1 >= gfp->decode_on_the_fly); + return gfp->decode_on_the_fly; + } + return 0; +} + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* DEPRECATED: now does the same as lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_input(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_input(const lame_global_flags *); + +/* DEPRECATED: now does the same as + lame_set_decode_on_the_fly() && lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_decode(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_decode(const lame_global_flags *); + +/* DEPRECATED: now does the same as lame_set_decode_on_the_fly() + default = 0 (disabled) */ +int CDECL lame_set_findPeakSample(lame_global_flags *, int); +int CDECL lame_get_findPeakSample(const lame_global_flags *); +#else +#endif + +/* DEPRECATED. same as lame_set_decode_on_the_fly() */ +int +lame_set_findPeakSample(lame_global_flags * gfp, int arg) +{ + return lame_set_decode_on_the_fly(gfp, arg); +} + +int +lame_get_findPeakSample(const lame_global_flags * gfp) +{ + return lame_get_decode_on_the_fly(gfp); +} + +/* DEPRECATED. same as lame_set_findReplayGain() */ +int +lame_set_ReplayGain_input(lame_global_flags * gfp, int arg) +{ + return lame_set_findReplayGain(gfp, arg); +} + +int +lame_get_ReplayGain_input(const lame_global_flags * gfp) +{ + return lame_get_findReplayGain(gfp); +} + +/* DEPRECATED. same as lame_set_decode_on_the_fly() && + lame_set_findReplayGain() */ +int +lame_set_ReplayGain_decode(lame_global_flags * gfp, int arg) +{ + if (lame_set_decode_on_the_fly(gfp, arg) < 0 || lame_set_findReplayGain(gfp, arg) < 0) + return -1; + else + return 0; +} + +int +lame_get_ReplayGain_decode(const lame_global_flags * gfp) +{ + if (lame_get_decode_on_the_fly(gfp) > 0 && lame_get_findReplayGain(gfp) > 0) + return 1; + else + return 0; +} + + +/* set and get some gapless encoding flags */ + +int +lame_set_nogap_total(lame_global_flags * gfp, int the_nogap_total) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->nogap_total = the_nogap_total; + return 0; + } + return -1; +} + +int +lame_get_nogap_total(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->nogap_total; + } + return 0; +} + +int +lame_set_nogap_currentindex(lame_global_flags * gfp, int the_nogap_index) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->nogap_current = the_nogap_index; + return 0; + } + return -1; +} + +int +lame_get_nogap_currentindex(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->nogap_current; + } + return 0; +} + + +/* message handlers */ +int +lame_set_errorf(lame_global_flags * gfp, void (*func) (const char *, va_list)) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->report.errorf = func; + return 0; + } + return -1; +} + +int +lame_set_debugf(lame_global_flags * gfp, void (*func) (const char *, va_list)) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->report.debugf = func; + return 0; + } + return -1; +} + +int +lame_set_msgf(lame_global_flags * gfp, void (*func) (const char *, va_list)) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->report.msgf = func; + return 0; + } + return -1; +} + + +/* + * Set one of + * - brate + * - compression ratio. + * + * Default is compression ratio of 11. + */ +int +lame_set_brate(lame_global_flags * gfp, int brate) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->brate = brate; + if (brate > 320) { + gfp->disable_reservoir = 1; + } + return 0; + } + return -1; +} + +int +lame_get_brate(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->brate; + } + return 0; +} + +int +lame_set_compression_ratio(lame_global_flags * gfp, float compression_ratio) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->compression_ratio = compression_ratio; + return 0; + } + return -1; +} + +float +lame_get_compression_ratio(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->compression_ratio; + } + return 0; +} + + + + +/* + * frame parameters + */ + +/* Mark as copyright protected. */ +int +lame_set_copyright(lame_global_flags * gfp, int copyright) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > copyright || 1 < copyright) + return -1; + gfp->copyright = copyright; + return 0; + } + return -1; +} + +int +lame_get_copyright(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->copyright && 1 >= gfp->copyright); + return gfp->copyright; + } + return 0; +} + + +/* Mark as original. */ +int +lame_set_original(lame_global_flags * gfp, int original) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 (enabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > original || 1 < original) + return -1; + gfp->original = original; + return 0; + } + return -1; +} + +int +lame_get_original(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->original && 1 >= gfp->original); + return gfp->original; + } + return 0; +} + + +/* + * error_protection. + * Use 2 bytes from each frame for CRC checksum. + */ +int +lame_set_error_protection(lame_global_flags * gfp, int error_protection) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > error_protection || 1 < error_protection) + return -1; + gfp->error_protection = error_protection; + return 0; + } + return -1; +} + +int +lame_get_error_protection(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->error_protection && 1 >= gfp->error_protection); + return gfp->error_protection; + } + return 0; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* padding_type. 0=pad no frames 1=pad all frames 2=adjust padding(default) */ +int CDECL lame_set_padding_type(lame_global_flags *, Padding_type); +Padding_type CDECL lame_get_padding_type(const lame_global_flags *); +#else +#endif + +/* + * padding_type. + * PAD_NO = pad no frames + * PAD_ALL = pad all frames + * PAD_ADJUST = adjust padding + */ +int +lame_set_padding_type(lame_global_flags * gfp, Padding_type padding_type) +{ + (void) gfp; + (void) padding_type; + return 0; +} + +Padding_type +lame_get_padding_type(const lame_global_flags * gfp) +{ + (void) gfp; + return PAD_ADJUST; +} + + +/* MP3 'private extension' bit. Meaningless. */ +int +lame_set_extension(lame_global_flags * gfp, int extension) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > extension || 1 < extension) + return -1; + gfp->extension = extension; + return 0; + } + return -1; +} + +int +lame_get_extension(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->extension && 1 >= gfp->extension); + return gfp->extension; + } + return 0; +} + + +/* Enforce strict ISO compliance. */ +int +lame_set_strict_ISO(lame_global_flags * gfp, int val) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (val < MDB_DEFAULT || MDB_MAXIMUM < val) + return -1; + gfp->strict_ISO = val; + return 0; + } + return -1; +} + +int +lame_get_strict_ISO(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->strict_ISO; + } + return 0; +} + + + + +/******************************************************************** + * quantization/noise shaping + ***********************************************************************/ + +/* Disable the bit reservoir. For testing only. */ +int +lame_set_disable_reservoir(lame_global_flags * gfp, int disable_reservoir) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > disable_reservoir || 1 < disable_reservoir) + return -1; + gfp->disable_reservoir = disable_reservoir; + return 0; + } + return -1; +} + +int +lame_get_disable_reservoir(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->disable_reservoir && 1 >= gfp->disable_reservoir); + return gfp->disable_reservoir; + } + return 0; +} + + + + +int +lame_set_experimentalX(lame_global_flags * gfp, int experimentalX) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_set_quant_comp(gfp, experimentalX); + lame_set_quant_comp_short(gfp, experimentalX); + return 0; + } + return -1; +} + +int +lame_get_experimentalX(const lame_global_flags * gfp) +{ + return lame_get_quant_comp(gfp); +} + + +/* Select a different "best quantization" function. default = 0 */ +int +lame_set_quant_comp(lame_global_flags * gfp, int quant_type) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->quant_comp = quant_type; + return 0; + } + return -1; +} + +int +lame_get_quant_comp(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->quant_comp; + } + return 0; +} + + +/* Select a different "best quantization" function. default = 0 */ +int +lame_set_quant_comp_short(lame_global_flags * gfp, int quant_type) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->quant_comp_short = quant_type; + return 0; + } + return -1; +} + +int +lame_get_quant_comp_short(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->quant_comp_short; + } + return 0; +} + + +/* Another experimental option. For testing only. */ +int +lame_set_experimentalY(lame_global_flags * gfp, int experimentalY) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->experimentalY = experimentalY; + return 0; + } + return -1; +} + +int +lame_get_experimentalY(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->experimentalY; + } + return 0; +} + + +int +lame_set_experimentalZ(lame_global_flags * gfp, int experimentalZ) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->experimentalZ = experimentalZ; + return 0; + } + return -1; +} + +int +lame_get_experimentalZ(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->experimentalZ; + } + return 0; +} + + +/* Naoki's psycho acoustic model. */ +int +lame_set_exp_nspsytune(lame_global_flags * gfp, int exp_nspsytune) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + gfp->exp_nspsytune = exp_nspsytune; + return 0; + } + return -1; +} + +int +lame_get_exp_nspsytune(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->exp_nspsytune; + } + return 0; +} + + + + +/******************************************************************** + * VBR control + ***********************************************************************/ + +/* Types of VBR. default = vbr_off = CBR */ +int +lame_set_VBR(lame_global_flags * gfp, vbr_mode VBR) +{ + if (is_lame_global_flags_valid(gfp)) { + int vbr_q = VBR; + if (0 > vbr_q || vbr_max_indicator <= vbr_q) + return -1; /* Unknown VBR mode! */ + gfp->VBR = VBR; + return 0; + } + return -1; +} + +vbr_mode +lame_get_VBR(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(gfp->VBR < vbr_max_indicator); + return gfp->VBR; + } + return vbr_off; +} + + +/* + * VBR quality level. + * 0 = highest + * 9 = lowest + */ +int +lame_set_VBR_q(lame_global_flags * gfp, int VBR_q) +{ + if (is_lame_global_flags_valid(gfp)) { + int ret = 0; + + if (0 > VBR_q) { + ret = -1; /* Unknown VBR quality level! */ + VBR_q = 0; + } + if (9 < VBR_q) { + ret = -1; + VBR_q = 9; + } + gfp->VBR_q = VBR_q; + gfp->VBR_q_frac = 0; + return ret; + } + return -1; +} + +int +lame_get_VBR_q(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->VBR_q && 10 > gfp->VBR_q); + return gfp->VBR_q; + } + return 0; +} + +int +lame_set_VBR_quality(lame_global_flags * gfp, float VBR_q) +{ + if (is_lame_global_flags_valid(gfp)) { + int ret = 0; + + if (0 > VBR_q) { + ret = -1; /* Unknown VBR quality level! */ + VBR_q = 0; + } + if (9.999 < VBR_q) { + ret = -1; + VBR_q = 9.999; + } + + gfp->VBR_q = (int) VBR_q; + gfp->VBR_q_frac = VBR_q - gfp->VBR_q; + + return ret; + } + return -1; +} + +float +lame_get_VBR_quality(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_q + gfp->VBR_q_frac; + } + return 0; +} + + +/* Ignored except for VBR = vbr_abr (ABR mode) */ +int +lame_set_VBR_mean_bitrate_kbps(lame_global_flags * gfp, int VBR_mean_bitrate_kbps) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->VBR_mean_bitrate_kbps = VBR_mean_bitrate_kbps; + return 0; + } + return -1; +} + +int +lame_get_VBR_mean_bitrate_kbps(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_mean_bitrate_kbps; + } + return 0; +} + +int +lame_set_VBR_min_bitrate_kbps(lame_global_flags * gfp, int VBR_min_bitrate_kbps) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->VBR_min_bitrate_kbps = VBR_min_bitrate_kbps; + return 0; + } + return -1; +} + +int +lame_get_VBR_min_bitrate_kbps(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_min_bitrate_kbps; + } + return 0; +} + +int +lame_set_VBR_max_bitrate_kbps(lame_global_flags * gfp, int VBR_max_bitrate_kbps) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->VBR_max_bitrate_kbps = VBR_max_bitrate_kbps; + return 0; + } + return -1; +} + +int +lame_get_VBR_max_bitrate_kbps(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_max_bitrate_kbps; + } + return 0; +} + + +/* + * Strictly enforce VBR_min_bitrate. + * Normally it will be violated for analog silence. + */ +int +lame_set_VBR_hard_min(lame_global_flags * gfp, int VBR_hard_min) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > VBR_hard_min || 1 < VBR_hard_min) + return -1; + + gfp->VBR_hard_min = VBR_hard_min; + + return 0; + } + return -1; +} + +int +lame_get_VBR_hard_min(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->VBR_hard_min && 1 >= gfp->VBR_hard_min); + return gfp->VBR_hard_min; + } + return 0; +} + + +/******************************************************************** + * Filtering control + ***********************************************************************/ + +/* + * Freqency in Hz to apply lowpass. + * 0 = default = lame chooses + * -1 = disabled + */ +int +lame_set_lowpassfreq(lame_global_flags * gfp, int lowpassfreq) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->lowpassfreq = lowpassfreq; + return 0; + } + return -1; +} + +int +lame_get_lowpassfreq(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->lowpassfreq; + } + return 0; +} + + +/* + * Width of transition band (in Hz). + * default = one polyphase filter band + */ +int +lame_set_lowpasswidth(lame_global_flags * gfp, int lowpasswidth) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->lowpasswidth = lowpasswidth; + return 0; + } + return -1; +} + +int +lame_get_lowpasswidth(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->lowpasswidth; + } + return 0; +} + + +/* + * Frequency in Hz to apply highpass. + * 0 = default = lame chooses + * -1 = disabled + */ +int +lame_set_highpassfreq(lame_global_flags * gfp, int highpassfreq) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->highpassfreq = highpassfreq; + return 0; + } + return -1; +} + +int +lame_get_highpassfreq(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->highpassfreq; + } + return 0; +} + + +/* + * Width of transition band (in Hz). + * default = one polyphase filter band + */ +int +lame_set_highpasswidth(lame_global_flags * gfp, int highpasswidth) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->highpasswidth = highpasswidth; + return 0; + } + return -1; +} + +int +lame_get_highpasswidth(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->highpasswidth; + } + return 0; +} + + + + +/* + * psycho acoustics and other arguments which you should not change + * unless you know what you are doing + */ + + +/* Adjust masking values. */ +int +lame_set_maskingadjust(lame_global_flags * gfp, float adjust) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->maskingadjust = adjust; + return 0; + } + return -1; +} + +float +lame_get_maskingadjust(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->maskingadjust; + } + return 0; +} + +int +lame_set_maskingadjust_short(lame_global_flags * gfp, float adjust) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->maskingadjust_short = adjust; + return 0; + } + return -1; +} + +float +lame_get_maskingadjust_short(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->maskingadjust_short; + } + return 0; +} + +/* Only use ATH for masking. */ +int +lame_set_ATHonly(lame_global_flags * gfp, int ATHonly) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATHonly = ATHonly; + return 0; + } + return -1; +} + +int +lame_get_ATHonly(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHonly; + } + return 0; +} + + +/* Only use ATH for short blocks. */ +int +lame_set_ATHshort(lame_global_flags * gfp, int ATHshort) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATHshort = ATHshort; + return 0; + } + return -1; +} + +int +lame_get_ATHshort(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHshort; + } + return 0; +} + + +/* Disable ATH. */ +int +lame_set_noATH(lame_global_flags * gfp, int noATH) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->noATH = noATH; + return 0; + } + return -1; +} + +int +lame_get_noATH(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->noATH; + } + return 0; +} + + +/* Select ATH formula. */ +int +lame_set_ATHtype(lame_global_flags * gfp, int ATHtype) +{ + if (is_lame_global_flags_valid(gfp)) { + /* XXX: ATHtype should be converted to an enum. */ + gfp->ATHtype = ATHtype; + return 0; + } + return -1; +} + +int +lame_get_ATHtype(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHtype; + } + return 0; +} + + +/* Select ATH formula 4 shape. */ +int +lame_set_ATHcurve(lame_global_flags * gfp, float ATHcurve) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATHcurve = ATHcurve; + return 0; + } + return -1; +} + +float +lame_get_ATHcurve(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHcurve; + } + return 0; +} + + +/* Lower ATH by this many db. */ +int +lame_set_ATHlower(lame_global_flags * gfp, float ATHlower) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATH_lower_db = ATHlower; + return 0; + } + return -1; +} + +float +lame_get_ATHlower(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATH_lower_db; + } + return 0; +} + + +/* Select ATH adaptive adjustment scheme. */ +int +lame_set_athaa_type(lame_global_flags * gfp, int athaa_type) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->athaa_type = athaa_type; + return 0; + } + return -1; +} + +int +lame_get_athaa_type(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->athaa_type; + } + return 0; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +int CDECL lame_set_athaa_loudapprox(lame_global_flags * gfp, int athaa_loudapprox); +int CDECL lame_get_athaa_loudapprox(const lame_global_flags * gfp); +#else +#endif + +/* Select the loudness approximation used by the ATH adaptive auto-leveling. */ +int +lame_set_athaa_loudapprox(lame_global_flags * gfp, int athaa_loudapprox) +{ + (void) gfp; + (void) athaa_loudapprox; + return 0; +} + +int +lame_get_athaa_loudapprox(const lame_global_flags * gfp) +{ + (void) gfp; + /* obsolete, the type known under number 2 is the only survival */ + return 2; +} + + +/* Adjust (in dB) the point below which adaptive ATH level adjustment occurs. */ +int +lame_set_athaa_sensitivity(lame_global_flags * gfp, float athaa_sensitivity) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->athaa_sensitivity = athaa_sensitivity; + return 0; + } + return -1; +} + +float +lame_get_athaa_sensitivity(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->athaa_sensitivity; + } + return 0; +} + + +/* Predictability limit (ISO tonality formula) */ +int lame_set_cwlimit(lame_global_flags * gfp, int cwlimit); +int lame_get_cwlimit(const lame_global_flags * gfp); + +int +lame_set_cwlimit(lame_global_flags * gfp, int cwlimit) +{ + (void) gfp; + (void) cwlimit; + return 0; +} + +int +lame_get_cwlimit(const lame_global_flags * gfp) +{ + (void) gfp; + return 0; +} + + + +/* + * Allow blocktypes to differ between channels. + * default: + * 0 for jstereo => block types coupled + * 1 for stereo => block types may differ + */ +int +lame_set_allow_diff_short(lame_global_flags * gfp, int allow_diff_short) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->short_blocks = allow_diff_short ? short_block_allowed : short_block_coupled; + return 0; + } + return -1; +} + +int +lame_get_allow_diff_short(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + if (gfp->short_blocks == short_block_allowed) + return 1; /* short blocks allowed to differ */ + else + return 0; /* not set, dispensed, forced or coupled */ + } + return 0; +} + + +/* Use temporal masking effect */ +int +lame_set_useTemporal(lame_global_flags * gfp, int useTemporal) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 (enabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 <= useTemporal && useTemporal <= 1) { + gfp->useTemporal = useTemporal; + return 0; + } + } + return -1; +} + +int +lame_get_useTemporal(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->useTemporal && 1 >= gfp->useTemporal); + return gfp->useTemporal; + } + return 0; +} + + +/* Use inter-channel masking effect */ +int +lame_set_interChRatio(lame_global_flags * gfp, float ratio) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0.0 (no inter-channel maskin) */ + if (0 <= ratio && ratio <= 1.0) { + gfp->interChRatio = ratio; + return 0; + } + } + return -1; +} + +float +lame_get_interChRatio(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert((0 <= gfp->interChRatio && gfp->interChRatio <= 1.0) || EQ(gfp->interChRatio, -1)); + return gfp->interChRatio; + } + return 0; +} + + +/* Use pseudo substep shaping method */ +int +lame_set_substep(lame_global_flags * gfp, int method) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0.0 (no substep noise shaping) */ + if (0 <= method && method <= 7) { + gfp->substep_shaping = method; + return 0; + } + } + return -1; +} + +int +lame_get_substep(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->substep_shaping && gfp->substep_shaping <= 7); + return gfp->substep_shaping; + } + return 0; +} + +/* scalefactors scale */ +int +lame_set_sfscale(lame_global_flags * gfp, int val) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->noise_shaping = (val != 0) ? 2 : 1; + return 0; + } + return -1; +} + +int +lame_get_sfscale(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return (gfp->noise_shaping == 2) ? 1 : 0; + } + return 0; +} + +/* subblock gain */ +int +lame_set_subblock_gain(lame_global_flags * gfp, int sbgain) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->subblock_gain = sbgain; + return 0; + } + return -1; +} + +int +lame_get_subblock_gain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->subblock_gain; + } + return 0; +} + + +/* Disable short blocks. */ +int +lame_set_no_short_blocks(lame_global_flags * gfp, int no_short_blocks) +{ + if (is_lame_global_flags_valid(gfp)) { + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 <= no_short_blocks && no_short_blocks <= 1) { + gfp->short_blocks = no_short_blocks ? short_block_dispensed : short_block_allowed; + return 0; + } + } + return -1; +} + +int +lame_get_no_short_blocks(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + switch (gfp->short_blocks) { + default: + case short_block_not_set: + return -1; + case short_block_dispensed: + return 1; + case short_block_allowed: + case short_block_coupled: + case short_block_forced: + return 0; + } + } + return -1; +} + + +/* Force short blocks. */ +int +lame_set_force_short_blocks(lame_global_flags * gfp, int short_blocks) +{ + if (is_lame_global_flags_valid(gfp)) { + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > short_blocks || 1 < short_blocks) + return -1; + + if (short_blocks == 1) + gfp->short_blocks = short_block_forced; + else if (gfp->short_blocks == short_block_forced) + gfp->short_blocks = short_block_allowed; + + return 0; + } + return -1; +} + +int +lame_get_force_short_blocks(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + switch (gfp->short_blocks) { + default: + case short_block_not_set: + return -1; + case short_block_dispensed: + case short_block_allowed: + case short_block_coupled: + return 0; + case short_block_forced: + return 1; + } + } + return -1; +} + +int +lame_set_short_threshold_lrm(lame_global_flags * gfp, float lrm) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->attackthre = lrm; + return 0; + } + return -1; +} + +float +lame_get_short_threshold_lrm(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->attackthre; + } + return 0; +} + +int +lame_set_short_threshold_s(lame_global_flags * gfp, float s) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->attackthre_s = s; + return 0; + } + return -1; +} + +float +lame_get_short_threshold_s(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->attackthre_s; + } + return 0; +} + +int +lame_set_short_threshold(lame_global_flags * gfp, float lrm, float s) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_set_short_threshold_lrm(gfp, lrm); + lame_set_short_threshold_s(gfp, s); + return 0; + } + return -1; +} + + +/* + * Input PCM is emphased PCM + * (for instance from one of the rarely emphased CDs). + * + * It is STRONGLY not recommended to use this, because psycho does not + * take it into account, and last but not least many decoders + * ignore these bits + */ +int +lame_set_emphasis(lame_global_flags * gfp, int emphasis) +{ + if (is_lame_global_flags_valid(gfp)) { + /* XXX: emphasis should be converted to an enum */ + if (0 <= emphasis && emphasis < 4) { + gfp->emphasis = emphasis; + return 0; + } + } + return -1; +} + +int +lame_get_emphasis(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->emphasis && gfp->emphasis < 4); + return gfp->emphasis; + } + return 0; +} + + + + +/***************************************************************/ +/* internal variables, cannot be set... */ +/* provided because they may be of use to calling application */ +/***************************************************************/ + +/* MPEG version. + * 0 = MPEG-2 + * 1 = MPEG-1 + * (2 = MPEG-2.5) + */ +int +lame_get_version(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->cfg.version; + } + } + return 0; +} + + +/* Encoder delay. */ +int +lame_get_encoder_delay(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_enc.encoder_delay; + } + } + return 0; +} + +/* padding added to the end of the input */ +int +lame_get_encoder_padding(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_enc.encoder_padding; + } + } + return 0; +} + + +/* Size of MPEG frame. */ +int +lame_get_framesize(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + return 576 * cfg->mode_gr; + } + } + return 0; +} + + +/* Number of frames encoded so far. */ +int +lame_get_frameNum(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_enc.frame_number; + } + } + return 0; +} + +int +lame_get_mf_samples_to_encode(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->sv_enc.mf_samples_to_encode; + } + } + return 0; +} + +int CDECL +lame_get_size_mp3buffer(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + int size; + compute_flushbits(gfc, &size); + return size; + } + } + return 0; +} + +int +lame_get_RadioGain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_rpg.RadioGain; + } + } + return 0; +} + +int +lame_get_AudiophileGain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return 0; + } + } + return 0; +} + +float +lame_get_PeakSample(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return (float) gfc->ov_rpg.PeakSample; + } + } + return 0; +} + +int +lame_get_noclipGainChange(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_rpg.noclipGainChange; + } + } + return 0; +} + +float +lame_get_noclipScale(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_rpg.noclipScale; + } + } + return 0; +} + + +/* + * LAME's estimate of the total number of frames to be encoded. + * Only valid if calling program set num_samples. + */ +int +lame_get_totalframes(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + unsigned long const pcm_samples_per_frame = 576 * cfg->mode_gr; + unsigned long pcm_samples_to_encode = gfp->num_samples; + unsigned long end_padding = 0; + int frames = 0; + + if (pcm_samples_to_encode == (0ul-1ul)) + return 0; /* unknown */ + + /* estimate based on user set num_samples: */ + if (cfg->samplerate_in != cfg->samplerate_out) { + /* resampling, estimate new samples_to_encode */ + double resampled_samples_to_encode = 0.0, frames_f = 0.0; + if (cfg->samplerate_in > 0) { + resampled_samples_to_encode = pcm_samples_to_encode; + resampled_samples_to_encode *= cfg->samplerate_out; + resampled_samples_to_encode /= cfg->samplerate_in; + } + if (resampled_samples_to_encode <= 0.0) + return 0; /* unlikely to happen, so what, no estimate! */ + frames_f = floor(resampled_samples_to_encode / pcm_samples_per_frame); + if (frames_f >= (INT_MAX-2)) + return 0; /* overflow, happens eventually, no estimate! */ + frames = frames_f; + resampled_samples_to_encode -= frames * pcm_samples_per_frame; + pcm_samples_to_encode = ceil(resampled_samples_to_encode); + } + else { + frames = pcm_samples_to_encode / pcm_samples_per_frame; + pcm_samples_to_encode -= frames * pcm_samples_per_frame; + } + pcm_samples_to_encode += 576ul; + end_padding = pcm_samples_per_frame - (pcm_samples_to_encode % pcm_samples_per_frame); + if (end_padding < 576ul) { + end_padding += pcm_samples_per_frame; + } + pcm_samples_to_encode += end_padding; + frames += (pcm_samples_to_encode / pcm_samples_per_frame); + /* check to see if we underestimated totalframes */ + /* if (totalframes < gfp->frameNum) */ + /* totalframes = gfp->frameNum; */ + return frames; + } + } + return 0; +} + + + + + +int +lame_set_preset(lame_global_flags * gfp, int preset) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->preset = preset; + return apply_preset(gfp, preset, 1); + } + return -1; +} + + + +int +lame_set_asm_optimizations(lame_global_flags * gfp, int optim, int mode) +{ + if (is_lame_global_flags_valid(gfp)) { + mode = (mode == 1 ? 1 : 0); + switch (optim) { + case MMX:{ + gfp->asm_optimizations.mmx = mode; + return optim; + } + case AMD_3DNOW:{ + gfp->asm_optimizations.amd3dnow = mode; + return optim; + } + case SSE:{ + gfp->asm_optimizations.sse = mode; + return optim; + } + default: + return optim; + } + } + return -1; +} + + +void +lame_set_write_id3tag_automatic(lame_global_flags * gfp, int v) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->write_id3tag_automatic = v; + } +} + + +int +lame_get_write_id3tag_automatic(lame_global_flags const *gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->write_id3tag_automatic; + } + return 1; +} + + +/* + +UNDOCUMENTED, experimental settings. These routines are not prototyped +in lame.h. You should not use them, they are experimental and may +change. + +*/ + + +/* + * just another daily changing developer switch + */ +void CDECL lame_set_tune(lame_global_flags *, float); + +void +lame_set_tune(lame_global_flags * gfp, float val) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->tune_value_a = val; + gfp->tune = 1; + } +} + +/* Custom msfix hack */ +void +lame_set_msfix(lame_global_flags * gfp, double msfix) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 */ + gfp->msfix = msfix; + } +} + +float +lame_get_msfix(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->msfix; + } + return 0; +} + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +int CDECL lame_set_preset_expopts(lame_global_flags *, int); +#else +#endif + +int +lame_set_preset_expopts(lame_global_flags * gfp, int preset_expopts) +{ + (void) gfp; + (void) preset_expopts; + return 0; +} + + +int +lame_set_preset_notune(lame_global_flags * gfp, int preset_notune) +{ + (void) gfp; + (void) preset_notune; + return 0; +} + +static int +calc_maximum_input_samples_for_buffer_size(lame_internal_flags const* gfc, size_t buffer_size) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int const pcm_samples_per_frame = 576 * cfg->mode_gr; + int frames_per_buffer = 0, input_samples_per_buffer = 0; + int kbps = 320; + + if (cfg->samplerate_out < 16000) + kbps = 64; + else if (cfg->samplerate_out < 32000) + kbps = 160; + else + kbps = 320; + if (cfg->free_format) + kbps = cfg->avg_bitrate; + else if (cfg->vbr == vbr_off) { + kbps = cfg->avg_bitrate; + } + { + int const pad = 1; + int const bpf = ((cfg->version + 1) * 72000 * kbps / cfg->samplerate_out + pad); + frames_per_buffer = buffer_size / bpf; + } + { + double ratio = (double) cfg->samplerate_in / cfg->samplerate_out; + input_samples_per_buffer = pcm_samples_per_frame * frames_per_buffer * ratio; + } + return input_samples_per_buffer; +} + +int +lame_get_maximum_number_of_samples(lame_t gfp, size_t buffer_size) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return calc_maximum_input_samples_for_buffer_size(gfc, buffer_size); + } + } + return LAME_GENERICERROR; +} diff --git a/pkg/lame/clame/set_get.h b/pkg/lame/clame/set_get.h new file mode 100644 index 0000000..37e4bcd --- /dev/null +++ b/pkg/lame/clame/set_get.h @@ -0,0 +1,76 @@ +/* + * set_get.h -- Internal set/get definitions + * + * Copyright (C) 2003 Gabriel Bouvigne / Lame project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SET_GET_H__ +#define __SET_GET_H__ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* select psychoacoustic model */ + +/* manage short blocks */ + int CDECL lame_set_short_threshold(lame_global_flags *, float, float); + int CDECL lame_set_short_threshold_lrm(lame_global_flags *, float); + float CDECL lame_get_short_threshold_lrm(const lame_global_flags *); + int CDECL lame_set_short_threshold_s(lame_global_flags *, float); + float CDECL lame_get_short_threshold_s(const lame_global_flags *); + + + int CDECL lame_set_maskingadjust(lame_global_flags *, float); + float CDECL lame_get_maskingadjust(const lame_global_flags *); + + int CDECL lame_set_maskingadjust_short(lame_global_flags *, float); + float CDECL lame_get_maskingadjust_short(const lame_global_flags *); + +/* select ATH formula 4 shape */ + int CDECL lame_set_ATHcurve(lame_global_flags *, float); + float CDECL lame_get_ATHcurve(const lame_global_flags *); + + int CDECL lame_set_preset_notune(lame_global_flags *, int); + +/* substep shaping method */ + int CDECL lame_set_substep(lame_global_flags *, int); + int CDECL lame_get_substep(const lame_global_flags *); + +/* scalefactors scale */ + int CDECL lame_set_sfscale(lame_global_flags *, int); + int CDECL lame_get_sfscale(const lame_global_flags *); + +/* subblock gain */ + int CDECL lame_set_subblock_gain(lame_global_flags *, int); + int CDECL lame_get_subblock_gain(const lame_global_flags *); + + + +/*presets*/ + int apply_preset(lame_global_flags *, int preset, int enforce); + + void CDECL lame_set_tune(lame_t, float); /* FOR INTERNAL USE ONLY */ + void CDECL lame_set_msfix(lame_t gfp, double msfix); + + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/pkg/lame/clame/tables.c b/pkg/lame/clame/tables.c new file mode 100644 index 0000000..a023099 --- /dev/null +++ b/pkg/lame/clame/tables.c @@ -0,0 +1,564 @@ +/* + * MPEG layer 3 tables source file + * + * Copyright (c) 1999 Albert L Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: tables.c,v 1.29 2011/05/07 16:05:17 rbrito Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "machine.h" + +#include "lame.h" +#include "tables.h" + + +static const uint16_t t1HB[] = { + 1, 1, + 1, 0 +}; + +static const uint16_t t2HB[] = { + 1, 2, 1, + 3, 1, 1, + 3, 2, 0 +}; + +static const uint16_t t3HB[] = { + 3, 2, 1, + 1, 1, 1, + 3, 2, 0 +}; + +static const uint16_t t5HB[] = { + 1, 2, 6, 5, + 3, 1, 4, 4, + 7, 5, 7, 1, + 6, 1, 1, 0 +}; + +static const uint16_t t6HB[] = { + 7, 3, 5, 1, + 6, 2, 3, 2, + 5, 4, 4, 1, + 3, 3, 2, 0 +}; + +static const uint16_t t7HB[] = { + 1, 2, 10, 19, 16, 10, + 3, 3, 7, 10, 5, 3, + 11, 4, 13, 17, 8, 4, + 12, 11, 18, 15, 11, 2, + 7, 6, 9, 14, 3, 1, + 6, 4, 5, 3, 2, 0 +}; + +static const uint16_t t8HB[] = { + 3, 4, 6, 18, 12, 5, + 5, 1, 2, 16, 9, 3, + 7, 3, 5, 14, 7, 3, + 19, 17, 15, 13, 10, 4, + 13, 5, 8, 11, 5, 1, + 12, 4, 4, 1, 1, 0 +}; + +static const uint16_t t9HB[] = { + 7, 5, 9, 14, 15, 7, + 6, 4, 5, 5, 6, 7, + 7, 6, 8, 8, 8, 5, + 15, 6, 9, 10, 5, 1, + 11, 7, 9, 6, 4, 1, + 14, 4, 6, 2, 6, 0 +}; + +static const uint16_t t10HB[] = { + 1, 2, 10, 23, 35, 30, 12, 17, + 3, 3, 8, 12, 18, 21, 12, 7, + 11, 9, 15, 21, 32, 40, 19, 6, + 14, 13, 22, 34, 46, 23, 18, 7, + 20, 19, 33, 47, 27, 22, 9, 3, + 31, 22, 41, 26, 21, 20, 5, 3, + 14, 13, 10, 11, 16, 6, 5, 1, + 9, 8, 7, 8, 4, 4, 2, 0 +}; + +static const uint16_t t11HB[] = { + 3, 4, 10, 24, 34, 33, 21, 15, + 5, 3, 4, 10, 32, 17, 11, 10, + 11, 7, 13, 18, 30, 31, 20, 5, + 25, 11, 19, 59, 27, 18, 12, 5, + 35, 33, 31, 58, 30, 16, 7, 5, + 28, 26, 32, 19, 17, 15, 8, 14, + 14, 12, 9, 13, 14, 9, 4, 1, + 11, 4, 6, 6, 6, 3, 2, 0 +}; + +static const uint16_t t12HB[] = { + 9, 6, 16, 33, 41, 39, 38, 26, + 7, 5, 6, 9, 23, 16, 26, 11, + 17, 7, 11, 14, 21, 30, 10, 7, + 17, 10, 15, 12, 18, 28, 14, 5, + 32, 13, 22, 19, 18, 16, 9, 5, + 40, 17, 31, 29, 17, 13, 4, 2, + 27, 12, 11, 15, 10, 7, 4, 1, + 27, 12, 8, 12, 6, 3, 1, 0 +}; + +static const uint16_t t13HB[] = { + 1, 5, 14, 21, 34, 51, 46, 71, 42, 52, 68, 52, 67, 44, 43, 19, + 3, 4, 12, 19, 31, 26, 44, 33, 31, 24, 32, 24, 31, 35, 22, 14, + 15, 13, 23, 36, 59, 49, 77, 65, 29, 40, 30, 40, 27, 33, 42, 16, + 22, 20, 37, 61, 56, 79, 73, 64, 43, 76, 56, 37, 26, 31, 25, 14, + 35, 16, 60, 57, 97, 75, 114, 91, 54, 73, 55, 41, 48, 53, 23, 24, + 58, 27, 50, 96, 76, 70, 93, 84, 77, 58, 79, 29, 74, 49, 41, 17, + 47, 45, 78, 74, 115, 94, 90, 79, 69, 83, 71, 50, 59, 38, 36, 15, + 72, 34, 56, 95, 92, 85, 91, 90, 86, 73, 77, 65, 51, 44, 43, 42, + 43, 20, 30, 44, 55, 78, 72, 87, 78, 61, 46, 54, 37, 30, 20, 16, + 53, 25, 41, 37, 44, 59, 54, 81, 66, 76, 57, 54, 37, 18, 39, 11, + 35, 33, 31, 57, 42, 82, 72, 80, 47, 58, 55, 21, 22, 26, 38, 22, + 53, 25, 23, 38, 70, 60, 51, 36, 55, 26, 34, 23, 27, 14, 9, 7, + 34, 32, 28, 39, 49, 75, 30, 52, 48, 40, 52, 28, 18, 17, 9, 5, + 45, 21, 34, 64, 56, 50, 49, 45, 31, 19, 12, 15, 10, 7, 6, 3, + 48, 23, 20, 39, 36, 35, 53, 21, 16, 23, 13, 10, 6, 1, 4, 2, + 16, 15, 17, 27, 25, 20, 29, 11, 17, 12, 16, 8, 1, 1, 0, 1 +}; + +static const uint16_t t15HB[] = { + 7, 12, 18, 53, 47, 76, 124, 108, 89, 123, 108, 119, 107, 81, 122, 63, + 13, 5, 16, 27, 46, 36, 61, 51, 42, 70, 52, 83, 65, 41, 59, 36, + 19, 17, 15, 24, 41, 34, 59, 48, 40, 64, 50, 78, 62, 80, 56, 33, + 29, 28, 25, 43, 39, 63, 55, 93, 76, 59, 93, 72, 54, 75, 50, 29, + 52, 22, 42, 40, 67, 57, 95, 79, 72, 57, 89, 69, 49, 66, 46, 27, + 77, 37, 35, 66, 58, 52, 91, 74, 62, 48, 79, 63, 90, 62, 40, 38, + 125, 32, 60, 56, 50, 92, 78, 65, 55, 87, 71, 51, 73, 51, 70, 30, + 109, 53, 49, 94, 88, 75, 66, 122, 91, 73, 56, 42, 64, 44, 21, 25, + 90, 43, 41, 77, 73, 63, 56, 92, 77, 66, 47, 67, 48, 53, 36, 20, + 71, 34, 67, 60, 58, 49, 88, 76, 67, 106, 71, 54, 38, 39, 23, 15, + 109, 53, 51, 47, 90, 82, 58, 57, 48, 72, 57, 41, 23, 27, 62, 9, + 86, 42, 40, 37, 70, 64, 52, 43, 70, 55, 42, 25, 29, 18, 11, 11, + 118, 68, 30, 55, 50, 46, 74, 65, 49, 39, 24, 16, 22, 13, 14, 7, + 91, 44, 39, 38, 34, 63, 52, 45, 31, 52, 28, 19, 14, 8, 9, 3, + 123, 60, 58, 53, 47, 43, 32, 22, 37, 24, 17, 12, 15, 10, 2, 1, + 71, 37, 34, 30, 28, 20, 17, 26, 21, 16, 10, 6, 8, 6, 2, 0 +}; + +static const uint16_t t16HB[] = { + 1, 5, 14, 44, 74, 63, 110, 93, 172, 149, 138, 242, 225, 195, 376, 17, + 3, 4, 12, 20, 35, 62, 53, 47, 83, 75, 68, 119, 201, 107, 207, 9, + 15, 13, 23, 38, 67, 58, 103, 90, 161, 72, 127, 117, 110, 209, 206, 16, + 45, 21, 39, 69, 64, 114, 99, 87, 158, 140, 252, 212, 199, 387, 365, 26, + 75, 36, 68, 65, 115, 101, 179, 164, 155, 264, 246, 226, 395, 382, 362, 9, + 66, 30, 59, 56, 102, 185, 173, 265, 142, 253, 232, 400, 388, 378, 445, 16, + 111, 54, 52, 100, 184, 178, 160, 133, 257, 244, 228, 217, 385, 366, 715, 10, + 98, 48, 91, 88, 165, 157, 148, 261, 248, 407, 397, 372, 380, 889, 884, 8, + 85, 84, 81, 159, 156, 143, 260, 249, 427, 401, 392, 383, 727, 713, 708, 7, + 154, 76, 73, 141, 131, 256, 245, 426, 406, 394, 384, 735, 359, 710, 352, 11, + 139, 129, 67, 125, 247, 233, 229, 219, 393, 743, 737, 720, 885, 882, 439, 4, + 243, 120, 118, 115, 227, 223, 396, 746, 742, 736, 721, 712, 706, 223, 436, 6, + 202, 224, 222, 218, 216, 389, 386, 381, 364, 888, 443, 707, 440, 437, 1728, 4, + 747, 211, 210, 208, 370, 379, 734, 723, 714, 1735, 883, 877, 876, 3459, 865, 2, + 377, 369, 102, 187, 726, 722, 358, 711, 709, 866, 1734, 871, 3458, 870, 434, 0, + 12, 10, 7, 11, 10, 17, 11, 9, 13, 12, 10, 7, 5, 3, 1, 3 +}; + +static const uint16_t t24HB[] = { + 15, 13, 46, 80, 146, 262, 248, 434, 426, 669, 653, 649, 621, 517, 1032, 88, + 14, 12, 21, 38, 71, 130, 122, 216, 209, 198, 327, 345, 319, 297, 279, 42, + 47, 22, 41, 74, 68, 128, 120, 221, 207, 194, 182, 340, 315, 295, 541, 18, + 81, 39, 75, 70, 134, 125, 116, 220, 204, 190, 178, 325, 311, 293, 271, 16, + 147, 72, 69, 135, 127, 118, 112, 210, 200, 188, 352, 323, 306, 285, 540, 14, + 263, 66, 129, 126, 119, 114, 214, 202, 192, 180, 341, 317, 301, 281, 262, 12, + 249, 123, 121, 117, 113, 215, 206, 195, 185, 347, 330, 308, 291, 272, 520, 10, + 435, 115, 111, 109, 211, 203, 196, 187, 353, 332, 313, 298, 283, 531, 381, 17, + 427, 212, 208, 205, 201, 193, 186, 177, 169, 320, 303, 286, 268, 514, 377, 16, + 335, 199, 197, 191, 189, 181, 174, 333, 321, 305, 289, 275, 521, 379, 371, 11, + 668, 184, 183, 179, 175, 344, 331, 314, 304, 290, 277, 530, 383, 373, 366, 10, + 652, 346, 171, 168, 164, 318, 309, 299, 287, 276, 263, 513, 375, 368, 362, 6, + 648, 322, 316, 312, 307, 302, 292, 284, 269, 261, 512, 376, 370, 364, 359, 4, + 620, 300, 296, 294, 288, 282, 273, 266, 515, 380, 374, 369, 365, 361, 357, 2, + 1033, 280, 278, 274, 267, 264, 259, 382, 378, 372, 367, 363, 360, 358, 356, 0, + 43, 20, 19, 17, 15, 13, 11, 9, 7, 6, 4, 7, 5, 3, 1, 3 +}; + +static const uint16_t t32HB[] = { + 1 << 0, 5 << 1, 4 << 1, 5 << 2, 6 << 1, 5 << 2, 4 << 2, 4 << 3, + 7 << 1, 3 << 2, 6 << 2, 0 << 3, 7 << 2, 2 << 3, 3 << 3, 1 << 4 +}; + +static const uint16_t t33HB[] = { + 15 << 0, 14 << 1, 13 << 1, 12 << 2, 11 << 1, 10 << 2, 9 << 2, 8 << 3, + 7 << 1, 6 << 2, 5 << 2, 4 << 3, 3 << 2, 2 << 3, 1 << 3, 0 << 4 +}; + + +const uint8_t t1l[] = { + 1, 4, + 3, 5 +}; + +static const uint8_t t2l[] = { + 1, 4, 7, + 4, 5, 7, + 6, 7, 8 +}; + +static const uint8_t t3l[] = { + 2, 3, 7, + 4, 4, 7, + 6, 7, 8 +}; + +static const uint8_t t5l[] = { + 1, 4, 7, 8, + 4, 5, 8, 9, + 7, 8, 9, 10, + 8, 8, 9, 10 +}; + +static const uint8_t t6l[] = { + 3, 4, 6, 8, + 4, 4, 6, 7, + 5, 6, 7, 8, + 7, 7, 8, 9 +}; + +static const uint8_t t7l[] = { + 1, 4, 7, 9, 9, 10, + 4, 6, 8, 9, 9, 10, + 7, 7, 9, 10, 10, 11, + 8, 9, 10, 11, 11, 11, + 8, 9, 10, 11, 11, 12, + 9, 10, 11, 12, 12, 12 +}; + +static const uint8_t t8l[] = { + 2, 4, 7, 9, 9, 10, + 4, 4, 6, 10, 10, 10, + 7, 6, 8, 10, 10, 11, + 9, 10, 10, 11, 11, 12, + 9, 9, 10, 11, 12, 12, + 10, 10, 11, 11, 13, 13 +}; + +static const uint8_t t9l[] = { + 3, 4, 6, 7, 9, 10, + 4, 5, 6, 7, 8, 10, + 5, 6, 7, 8, 9, 10, + 7, 7, 8, 9, 9, 10, + 8, 8, 9, 9, 10, 11, + 9, 9, 10, 10, 11, 11 +}; + +static const uint8_t t10l[] = { + 1, 4, 7, 9, 10, 10, 10, 11, + 4, 6, 8, 9, 10, 11, 10, 10, + 7, 8, 9, 10, 11, 12, 11, 11, + 8, 9, 10, 11, 12, 12, 11, 12, + 9, 10, 11, 12, 12, 12, 12, 12, + 10, 11, 12, 12, 13, 13, 12, 13, + 9, 10, 11, 12, 12, 12, 13, 13, + 10, 10, 11, 12, 12, 13, 13, 13 +}; + +static const uint8_t t11l[] = { + 2, 4, 6, 8, 9, 10, 9, 10, + 4, 5, 6, 8, 10, 10, 9, 10, + 6, 7, 8, 9, 10, 11, 10, 10, + 8, 8, 9, 11, 10, 12, 10, 11, + 9, 10, 10, 11, 11, 12, 11, 12, + 9, 10, 11, 12, 12, 13, 12, 13, + 9, 9, 9, 10, 11, 12, 12, 12, + 9, 9, 10, 11, 12, 12, 12, 12 +}; + +static const uint8_t t12l[] = { + 4, 4, 6, 8, 9, 10, 10, 10, + 4, 5, 6, 7, 9, 9, 10, 10, + 6, 6, 7, 8, 9, 10, 9, 10, + 7, 7, 8, 8, 9, 10, 10, 10, + 8, 8, 9, 9, 10, 10, 10, 11, + 9, 9, 10, 10, 10, 11, 10, 11, + 9, 9, 9, 10, 10, 11, 11, 12, + 10, 10, 10, 11, 11, 11, 11, 12 +}; + +static const uint8_t t13l[] = { + 1, 5, 7, 8, 9, 10, 10, 11, 10, 11, 12, 12, 13, 13, 14, 14, + 4, 6, 8, 9, 10, 10, 11, 11, 11, 11, 12, 12, 13, 14, 14, 14, + 7, 8, 9, 10, 11, 11, 12, 12, 11, 12, 12, 13, 13, 14, 15, 15, + 8, 9, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 15, 15, + 9, 9, 11, 11, 12, 12, 13, 13, 12, 13, 13, 14, 14, 15, 15, 16, + 10, 10, 11, 12, 12, 12, 13, 13, 13, 13, 14, 13, 15, 15, 16, 16, + 10, 11, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, + 11, 11, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 18, 18, + 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 15, 15, 16, 17, 17, + 11, 11, 12, 12, 13, 13, 13, 15, 14, 15, 15, 16, 16, 16, 18, 17, + 11, 12, 12, 13, 13, 14, 14, 15, 14, 15, 16, 15, 16, 17, 18, 19, + 12, 12, 12, 13, 14, 14, 14, 14, 15, 15, 15, 16, 17, 17, 17, 18, + 12, 13, 13, 14, 14, 15, 14, 15, 16, 16, 17, 17, 17, 18, 18, 18, + 13, 13, 14, 15, 15, 15, 16, 16, 16, 16, 16, 17, 18, 17, 18, 18, + 14, 14, 14, 15, 15, 15, 17, 16, 16, 19, 17, 17, 17, 19, 18, 18, + 13, 14, 15, 16, 16, 16, 17, 16, 17, 17, 18, 18, 21, 20, 21, 18 +}; + +static const uint8_t t15l[] = { + 3, 5, 6, 8, 8, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 14, + 5, 5, 7, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, + 6, 7, 7, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 13, + 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 14, + 10, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 14, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, + 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 15, 14, + 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, + 12, 12, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 15, 15, + 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 14, 15, + 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15 +}; + +static const uint8_t t16_5l[] = { + 1, 5, 7, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 11, + 4, 6, 8, 9, 10, 11, 11, 11, 12, 12, 12, 13, 14, 13, 14, 11, + 7, 8, 9, 10, 11, 11, 12, 12, 13, 12, 13, 13, 13, 14, 14, 12, + 9, 9, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 13, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 12, + 10, 10, 11, 11, 12, 13, 13, 14, 13, 14, 14, 15, 15, 15, 16, 13, + 11, 11, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 13, + 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 17, 17, 13, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 13, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 16, 15, 14, + 12, 13, 12, 13, 14, 14, 14, 14, 15, 16, 16, 16, 17, 17, 16, 13, + 13, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, 16, 15, 16, 14, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 16, 16, 16, 16, 18, 14, + 15, 14, 14, 14, 15, 15, 16, 16, 16, 18, 17, 17, 17, 19, 17, 14, + 14, 15, 13, 14, 16, 16, 15, 16, 16, 17, 18, 17, 19, 17, 16, 14, + 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 12 +}; + +static const uint8_t t16l[] = { + 1, 5, 7, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 10, + 4, 6, 8, 9, 10, 11, 11, 11, 12, 12, 12, 13, 14, 13, 14, 10, + 7, 8, 9, 10, 11, 11, 12, 12, 13, 12, 13, 13, 13, 14, 14, 11, + 9, 9, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 12, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 11, + 10, 10, 11, 11, 12, 13, 13, 14, 13, 14, 14, 15, 15, 15, 16, 12, + 11, 11, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 12, + 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 17, 17, 12, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 12, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 16, 15, 13, + 12, 13, 12, 13, 14, 14, 14, 14, 15, 16, 16, 16, 17, 17, 16, 12, + 13, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, 16, 15, 16, 13, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 16, 16, 16, 16, 18, 13, + 15, 14, 14, 14, 15, 15, 16, 16, 16, 18, 17, 17, 17, 19, 17, 13, + 14, 15, 13, 14, 16, 16, 15, 16, 16, 17, 18, 17, 19, 17, 16, 13, + 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 10 +}; + +static const uint8_t t24l[] = { + 4, 5, 7, 8, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 13, 10, + 5, 6, 7, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 12, 10, + 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 9, + 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 9, + 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 9, + 10, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 9, + 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 9, + 11, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 10, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 10, + 12, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 10, + 12, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 10, + 13, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 6 +}; + +const uint8_t t32l[] = { + 1 + 0, 4 + 1, 4 + 1, 5 + 2, 4 + 1, 6 + 2, 5 + 2, 6 + 3, + 4 + 1, 5 + 2, 5 + 2, 6 + 3, 5 + 2, 6 + 3, 6 + 3, 6 + 4 +}; + +const uint8_t t33l[] = { + 4 + 0, 4 + 1, 4 + 1, 4 + 2, 4 + 1, 4 + 2, 4 + 2, 4 + 3, + 4 + 1, 4 + 2, 4 + 2, 4 + 3, 4 + 2, 4 + 3, 4 + 3, 4 + 4 +}; + + +const struct huffcodetab ht[HTN] = { + /* xlen, linmax, table, hlen */ + {0, 0, NULL, NULL}, + {2, 0, t1HB, t1l}, + {3, 0, t2HB, t2l}, + {3, 0, t3HB, t3l}, + {0, 0, NULL, NULL}, /* Apparently not used */ + {4, 0, t5HB, t5l}, + {4, 0, t6HB, t6l}, + {6, 0, t7HB, t7l}, + {6, 0, t8HB, t8l}, + {6, 0, t9HB, t9l}, + {8, 0, t10HB, t10l}, + {8, 0, t11HB, t11l}, + {8, 0, t12HB, t12l}, + {16, 0, t13HB, t13l}, + {0, 0, NULL, t16_5l}, /* Apparently not used */ + {16, 0, t15HB, t15l}, + + {1, 1, t16HB, t16l}, + {2, 3, t16HB, t16l}, + {3, 7, t16HB, t16l}, + {4, 15, t16HB, t16l}, + {6, 63, t16HB, t16l}, + {8, 255, t16HB, t16l}, + {10, 1023, t16HB, t16l}, + {13, 8191, t16HB, t16l}, + + {4, 15, t24HB, t24l}, + {5, 31, t24HB, t24l}, + {6, 63, t24HB, t24l}, + {7, 127, t24HB, t24l}, + {8, 255, t24HB, t24l}, + {9, 511, t24HB, t24l}, + {11, 2047, t24HB, t24l}, + {13, 8191, t24HB, t24l}, + + {0, 0, t32HB, t32l}, + {0, 0, t33HB, t33l}, +}; + + + + + +/* for (i = 0; i < 16*16; i++) { + * largetbl[i] = ((ht[16].hlen[i]) << 16) + ht[24].hlen[i]; + * } + */ +const uint32_t largetbl[16 * 16] = { + 0x010004, 0x050005, 0x070007, 0x090008, 0x0a0009, 0x0a000a, 0x0b000a, 0x0b000b, + 0x0c000b, 0x0c000c, 0x0c000c, 0x0d000c, 0x0d000c, 0x0d000c, 0x0e000d, 0x0a000a, + 0x040005, 0x060006, 0x080007, 0x090008, 0x0a0009, 0x0b000a, 0x0b000a, 0x0b000b, + 0x0c000b, 0x0c000b, 0x0c000c, 0x0d000c, 0x0e000c, 0x0d000c, 0x0e000c, 0x0a000a, + 0x070007, 0x080007, 0x090008, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000b, + 0x0d000b, 0x0c000b, 0x0d000b, 0x0d000c, 0x0d000c, 0x0e000c, 0x0e000d, 0x0b0009, + 0x090008, 0x090008, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000a, 0x0c000b, + 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0c0009, + 0x0a0009, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000a, 0x0d000a, 0x0d000b, + 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000d, 0x0b0009, + 0x0a000a, 0x0a0009, 0x0b000a, 0x0b000a, 0x0c000a, 0x0d000a, 0x0d000b, 0x0e000b, + 0x0d000b, 0x0e000b, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x0c0009, + 0x0b000a, 0x0b000a, 0x0b000a, 0x0c000a, 0x0d000a, 0x0d000b, 0x0d000b, 0x0d000b, + 0x0e000b, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x10000d, 0x0c0009, + 0x0b000b, 0x0b000a, 0x0c000a, 0x0c000a, 0x0d000b, 0x0d000b, 0x0d000b, 0x0e000b, + 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x11000d, 0x11000d, 0x0c000a, + 0x0b000b, 0x0c000b, 0x0c000b, 0x0d000b, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000b, + 0x0f000b, 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x10000d, 0x10000d, 0x0c000a, + 0x0c000b, 0x0c000b, 0x0c000b, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000b, 0x0f000c, + 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x0f000d, 0x10000d, 0x0f000d, 0x0d000a, + 0x0c000c, 0x0d000b, 0x0c000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0e000c, + 0x0f000c, 0x10000c, 0x10000c, 0x10000d, 0x11000d, 0x11000d, 0x10000d, 0x0c000a, + 0x0d000c, 0x0d000c, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0f000c, 0x10000c, + 0x10000c, 0x10000c, 0x10000c, 0x10000d, 0x10000d, 0x0f000d, 0x10000d, 0x0d000a, + 0x0d000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, + 0x0f000c, 0x11000c, 0x10000d, 0x10000d, 0x10000d, 0x10000d, 0x12000d, 0x0d000a, + 0x0f000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x10000c, 0x10000c, + 0x10000d, 0x12000d, 0x11000d, 0x11000d, 0x11000d, 0x13000d, 0x11000d, 0x0d000a, + 0x0e000d, 0x0f000c, 0x0d000c, 0x0e000c, 0x10000c, 0x10000c, 0x0f000c, 0x10000d, + 0x10000d, 0x11000d, 0x12000d, 0x11000d, 0x13000d, 0x11000d, 0x10000d, 0x0d000a, + 0x0a0009, 0x0a0009, 0x0a0009, 0x0b0009, 0x0b0009, 0x0c0009, 0x0c0009, 0x0c0009, + 0x0d0009, 0x0d0009, 0x0d0009, 0x0d000a, 0x0d000a, 0x0d000a, 0x0d000a, 0x0a0006 +}; + +/* for (i = 0; i < 3*3; i++) { + * table23[i] = ((ht[2].hlen[i]) << 16) + ht[3].hlen[i]; + * } + */ +const uint32_t table23[3 * 3] = { + 0x010002, 0x040003, 0x070007, + 0x040004, 0x050004, 0x070007, + 0x060006, 0x070007, 0x080008 +}; + +/* for (i = 0; i < 4*4; i++) { + * table56[i] = ((ht[5].hlen[i]) << 16) + ht[6].hlen[i]; + * } + */ +const uint32_t table56[4 * 4] = { + 0x010003, 0x040004, 0x070006, 0x080008, 0x040004, 0x050004, 0x080006, 0x090007, + 0x070005, 0x080006, 0x090007, 0x0a0008, 0x080007, 0x080007, 0x090008, 0x0a0009 +}; + + + +/* + * 0: MPEG-2 LSF + * 1: MPEG-1 + * 2: MPEG-2.5 LSF FhG extention (1995-07-11 shn) + */ + +typedef enum { + MPEG_2 = 0, + MPEG_1 = 1, + MPEG_25 = 2 +} MPEG_t; + +const int bitrate_table[3][16] = { + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}, /* MPEG 2 */ + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1}, /* MPEG 1 */ + {0, 8, 16, 24, 32, 40, 48, 56, 64, -1, -1, -1, -1, -1, -1, -1}, /* MPEG 2.5 */ +}; + +const int samplerate_table[3][4] = { + {22050, 24000, 16000, -1}, /* MPEG 2 */ + {44100, 48000, 32000, -1}, /* MPEG 1 */ + {11025, 12000, 8000, -1}, /* MPEG 2.5 */ +}; + +int +lame_get_bitrate(int mpeg_version, int table_index) +{ + if (0 <= mpeg_version && mpeg_version <= 2) { + if (0 <= table_index && table_index <= 15) { + return bitrate_table[mpeg_version][table_index]; + } + } + return -1; +} + +int +lame_get_samplerate(int mpeg_version, int table_index) +{ + if (0 <= mpeg_version && mpeg_version <= 2) { + if (0 <= table_index && table_index <= 3) { + return samplerate_table[mpeg_version][table_index]; + } + } + return -1; +} + + +/* This is the scfsi_band table from 2.4.2.7 of the IS */ +const int scfsi_band[5] = { 0, 6, 11, 16, 21 }; + +/* end of tables.c */ diff --git a/pkg/lame/clame/tables.h b/pkg/lame/clame/tables.h new file mode 100644 index 0000000..0dd7deb --- /dev/null +++ b/pkg/lame/clame/tables.h @@ -0,0 +1,95 @@ +/* + * MPEG layer 3 tables include file + * + * Copyright (c) 1999 Albert L Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_TABLES_H +#define LAME_TABLES_H + +#if 0 +typedef struct { + unsigned char no; + unsigned char width; + unsigned char minval_2; + float quiet_thr; + float norm; + float bark; +} type1_t; + +typedef struct { + unsigned char no; + unsigned char width; + float quiet_thr; + float norm; + float SNR; + float bark; +} type2_t; + +typedef struct { + unsigned int no:5; + unsigned int cbw:3; + unsigned int bu:6; + unsigned int bo:6; + unsigned int w1_576:10; + unsigned int w2_576:10; +} type34_t; + +typedef struct { + size_t len1; + const type1_t *const tab1; + size_t len2; + const type2_t *const tab2; + size_t len3; + const type34_t *const tab3; + size_t len4; + const type34_t *const tab4; +} type5_t; + +extern const type5_t table5[6]; + +#endif + +#define HTN 34 + +struct huffcodetab { + const unsigned int xlen; /* max. x-index+ */ + const unsigned int linmax; /* max number to be stored in linbits */ + const uint16_t *table; /* pointer to array[xlen][ylen] */ + const uint8_t *hlen; /* pointer to array[xlen][ylen] */ +}; + +extern const struct huffcodetab ht[HTN]; + /* global memory block */ + /* array of all huffcodtable headers */ + /* 0..31 Huffman code table 0..31 */ + /* 32,33 count1-tables */ + +extern const uint8_t t32l[]; +extern const uint8_t t33l[]; + +extern const uint32_t largetbl[16 * 16]; +extern const uint32_t table23[3 * 3]; +extern const uint32_t table56[4 * 4]; + +extern const int scfsi_band[5]; + +extern const int bitrate_table [3][16]; +extern const int samplerate_table [3][ 4]; + +#endif /* LAME_TABLES_H */ diff --git a/pkg/lame/clame/takehiro.c b/pkg/lame/clame/takehiro.c new file mode 100644 index 0000000..67aba1b --- /dev/null +++ b/pkg/lame/clame/takehiro.c @@ -0,0 +1,1375 @@ +/* + * MP3 huffman table selecting and bit counting + * + * Copyright (c) 1999-2005 Takehiro TOMINAGA + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: takehiro.c,v 1.80 2017/09/06 15:07:30 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "quantize_pvt.h" +#include "tables.h" + + +static const struct { + const int region0_count; + const int region1_count; +} subdv_table[23] = { + { + 0, 0}, /* 0 bands */ + { + 0, 0}, /* 1 bands */ + { + 0, 0}, /* 2 bands */ + { + 0, 0}, /* 3 bands */ + { + 0, 0}, /* 4 bands */ + { + 0, 1}, /* 5 bands */ + { + 1, 1}, /* 6 bands */ + { + 1, 1}, /* 7 bands */ + { + 1, 2}, /* 8 bands */ + { + 2, 2}, /* 9 bands */ + { + 2, 3}, /* 10 bands */ + { + 2, 3}, /* 11 bands */ + { + 3, 4}, /* 12 bands */ + { + 3, 4}, /* 13 bands */ + { + 3, 4}, /* 14 bands */ + { + 4, 5}, /* 15 bands */ + { + 4, 5}, /* 16 bands */ + { + 4, 6}, /* 17 bands */ + { + 5, 6}, /* 18 bands */ + { + 5, 6}, /* 19 bands */ + { + 5, 7}, /* 20 bands */ + { + 6, 7}, /* 21 bands */ + { + 6, 7}, /* 22 bands */ +}; + + + + + +/********************************************************************* + * nonlinear quantization of xr + * More accurate formula than the ISO formula. Takes into account + * the fact that we are quantizing xr -> ix, but we want ix^4/3 to be + * as close as possible to x^4/3. (taking the nearest int would mean + * ix is as close as possible to xr, which is different.) + * + * From Segher Boessenkool 11/1999 + * + * 09/2000: ASM code removed in favor of IEEE754 hack by Takehiro + * Tominaga. If you need the ASM code, check CVS circa Aug 2000. + * + * 01/2004: Optimizations by Gabriel Bouvigne + *********************************************************************/ + + + + + +static void +quantize_lines_xrpow_01(unsigned int l, FLOAT istep, const FLOAT * xr, int *ix) +{ + const FLOAT compareval0 = (1.0f - 0.4054f) / istep; + unsigned int i; + + assert(l > 0); + assert(l % 2 == 0); + for (i = 0; i < l; i += 2) { + FLOAT const xr_0 = xr[i+0]; + FLOAT const xr_1 = xr[i+1]; + int const ix_0 = (compareval0 > xr_0) ? 0 : 1; + int const ix_1 = (compareval0 > xr_1) ? 0 : 1; + ix[i+0] = ix_0; + ix[i+1] = ix_1; + } +} + + + +#ifdef TAKEHIRO_IEEE754_HACK + +typedef union { + float f; + int i; +} fi_union; + +#define MAGIC_FLOAT (65536*(128)) +#define MAGIC_INT 0x4b000000 + + +static void +quantize_lines_xrpow(unsigned int l, FLOAT istep, const FLOAT * xp, int *pi) +{ + fi_union *fi; + unsigned int remaining; + + assert(l > 0); + + fi = (fi_union *) pi; + + l = l >> 1; + remaining = l % 2; + l = l >> 1; + while (l--) { + double x0 = istep * xp[0]; + double x1 = istep * xp[1]; + double x2 = istep * xp[2]; + double x3 = istep * xp[3]; + + x0 += MAGIC_FLOAT; + fi[0].f = x0; + x1 += MAGIC_FLOAT; + fi[1].f = x1; + x2 += MAGIC_FLOAT; + fi[2].f = x2; + x3 += MAGIC_FLOAT; + fi[3].f = x3; + + fi[0].f = x0 + adj43asm[fi[0].i - MAGIC_INT]; + fi[1].f = x1 + adj43asm[fi[1].i - MAGIC_INT]; + fi[2].f = x2 + adj43asm[fi[2].i - MAGIC_INT]; + fi[3].f = x3 + adj43asm[fi[3].i - MAGIC_INT]; + + fi[0].i -= MAGIC_INT; + fi[1].i -= MAGIC_INT; + fi[2].i -= MAGIC_INT; + fi[3].i -= MAGIC_INT; + fi += 4; + xp += 4; + }; + if (remaining) { + double x0 = istep * xp[0]; + double x1 = istep * xp[1]; + + x0 += MAGIC_FLOAT; + fi[0].f = x0; + x1 += MAGIC_FLOAT; + fi[1].f = x1; + + fi[0].f = x0 + adj43asm[fi[0].i - MAGIC_INT]; + fi[1].f = x1 + adj43asm[fi[1].i - MAGIC_INT]; + + fi[0].i -= MAGIC_INT; + fi[1].i -= MAGIC_INT; + } + +} + + +#else + +/********************************************************************* + * XRPOW_FTOI is a macro to convert floats to ints. + * if XRPOW_FTOI(x) = nearest_int(x), then QUANTFAC(x)=adj43asm[x] + * ROUNDFAC= -0.0946 + * + * if XRPOW_FTOI(x) = floor(x), then QUANTFAC(x)=asj43[x] + * ROUNDFAC=0.4054 + * + * Note: using floor() or (int) is extremely slow. On machines where + * the TAKEHIRO_IEEE754_HACK code above does not work, it is worthwile + * to write some ASM for XRPOW_FTOI(). + *********************************************************************/ +#define XRPOW_FTOI(src,dest) ((dest) = (int)(src)) +#define QUANTFAC(rx) adj43[rx] +#define ROUNDFAC 0.4054 + + +static void +quantize_lines_xrpow(unsigned int l, FLOAT istep, const FLOAT * xr, int *ix) +{ + unsigned int remaining; + + assert(l > 0); + + l = l >> 1; + remaining = l % 2; + l = l >> 1; + while (l--) { + FLOAT x0, x1, x2, x3; + int rx0, rx1, rx2, rx3; + + x0 = *xr++ * istep; + x1 = *xr++ * istep; + XRPOW_FTOI(x0, rx0); + x2 = *xr++ * istep; + XRPOW_FTOI(x1, rx1); + x3 = *xr++ * istep; + XRPOW_FTOI(x2, rx2); + x0 += QUANTFAC(rx0); + XRPOW_FTOI(x3, rx3); + x1 += QUANTFAC(rx1); + XRPOW_FTOI(x0, *ix++); + x2 += QUANTFAC(rx2); + XRPOW_FTOI(x1, *ix++); + x3 += QUANTFAC(rx3); + XRPOW_FTOI(x2, *ix++); + XRPOW_FTOI(x3, *ix++); + }; + if (remaining) { + FLOAT x0, x1; + int rx0, rx1; + + x0 = *xr++ * istep; + x1 = *xr++ * istep; + XRPOW_FTOI(x0, rx0); + XRPOW_FTOI(x1, rx1); + x0 += QUANTFAC(rx0); + x1 += QUANTFAC(rx1); + XRPOW_FTOI(x0, *ix++); + XRPOW_FTOI(x1, *ix++); + } + +} + + + +#endif + + + +/********************************************************************* + * Quantization function + * This function will select which lines to quantize and call the + * proper quantization function + *********************************************************************/ + +static void +quantize_xrpow(const FLOAT * xp, int *pi, FLOAT istep, gr_info const *const cod_info, + calc_noise_data const *prev_noise) +{ + /* quantize on xr^(3/4) instead of xr */ + int sfb; + int sfbmax; + int j = 0; + int prev_data_use; + int *iData; + int accumulate = 0; + int accumulate01 = 0; + int *acc_iData; + const FLOAT *acc_xp; + + iData = pi; + acc_xp = xp; + acc_iData = iData; + + + /* Reusing previously computed data does not seems to work if global gain + is changed. Finding why it behaves this way would allow to use a cache of + previously computed values (let's 10 cached values per sfb) that would + probably provide a noticeable speedup */ + prev_data_use = (prev_noise && (cod_info->global_gain == prev_noise->global_gain)); + + if (cod_info->block_type == SHORT_TYPE) + sfbmax = 38; + else + sfbmax = 21; + + for (sfb = 0; sfb <= sfbmax; sfb++) { + int step = -1; + + if (prev_data_use || cod_info->block_type == NORM_TYPE) { + step = + cod_info->global_gain + - ((cod_info->scalefac[sfb] + (cod_info->preflag ? pretab[sfb] : 0)) + << (cod_info->scalefac_scale + 1)) + - cod_info->subblock_gain[cod_info->window[sfb]] * 8; + } + assert(cod_info->width[sfb] >= 0); + if (prev_data_use && (prev_noise->step[sfb] == step)) { + /* do not recompute this part, + but compute accumulated lines */ + if (accumulate) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + } + if (accumulate01) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + } + } + else { /*should compute this part */ + int l; + l = cod_info->width[sfb]; + + if ((j + cod_info->width[sfb]) > cod_info->max_nonzero_coeff) { + /*do not compute upper zero part */ + int usefullsize; + usefullsize = cod_info->max_nonzero_coeff - j + 1; + memset(&pi[cod_info->max_nonzero_coeff], 0, + sizeof(int) * (576 - cod_info->max_nonzero_coeff)); + l = usefullsize; + + if (l < 0) { + l = 0; + } + + /* no need to compute higher sfb values */ + sfb = sfbmax + 1; + } + + /*accumulate lines to quantize */ + if (!accumulate && !accumulate01) { + acc_iData = iData; + acc_xp = xp; + } + if (prev_noise && + prev_noise->sfb_count1 > 0 && + sfb >= prev_noise->sfb_count1 && + prev_noise->step[sfb] > 0 && step >= prev_noise->step[sfb]) { + + if (accumulate) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + acc_iData = iData; + acc_xp = xp; + } + accumulate01 += l; + } + else { + if (accumulate01) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + acc_iData = iData; + acc_xp = xp; + } + accumulate += l; + } + + if (l <= 0) { + /* rh: 20040215 + * may happen due to "prev_data_use" optimization + */ + if (accumulate01) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + } + if (accumulate) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + } + + break; /* ends for-loop */ + } + } + if (sfb <= sfbmax) { + iData += cod_info->width[sfb]; + xp += cod_info->width[sfb]; + j += cod_info->width[sfb]; + } + } + if (accumulate) { /*last data part */ + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + } + if (accumulate01) { /*last data part */ + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + } + +} + + + + +/*************************************************************************/ +/* ix_max */ +/*************************************************************************/ + +static int +ix_max(const int *ix, const int *end) +{ + int max1 = 0, max2 = 0; + + do { + int const x1 = *ix++; + int const x2 = *ix++; + if (max1 < x1) + max1 = x1; + + if (max2 < x2) + max2 = x2; + } while (ix < end); + if (max1 < max2) + max1 = max2; + return max1; +} + + + + + + + + +static int +count_bit_ESC(const int *ix, const int *const end, int t1, const int t2, unsigned int *const s) +{ + /* ESC-table is used */ + unsigned int const linbits = ht[t1].xlen * 65536u + ht[t2].xlen; + unsigned int sum = 0, sum2; + + do { + unsigned int x = *ix++; + unsigned int y = *ix++; + + if (x >= 15u) { + x = 15u; + sum += linbits; + } + if (y >= 15u) { + y = 15u; + sum += linbits; + } + x <<= 4u; + x += y; + sum += largetbl[x]; + } while (ix < end); + + sum2 = sum & 0xffffu; + sum >>= 16u; + + if (sum > sum2) { + sum = sum2; + t1 = t2; + } + + *s += sum; + return t1; +} + + +static int +count_bit_noESC(const int *ix, const int *end, int mx, unsigned int *s) +{ + /* No ESC-words */ + unsigned int sum1 = 0; + const uint8_t *const hlen1 = ht[1].hlen; + (void) mx; + + do { + unsigned int const x0 = *ix++; + unsigned int const x1 = *ix++; + sum1 += hlen1[ x0+x0 + x1 ]; + } while (ix < end); + + *s += sum1; + return 1; +} + + +static const int huf_tbl_noESC[] = { + 1, 2, 5, 7, 7, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13 +}; + + +static int +count_bit_noESC_from2(const int *ix, const int *end, int max, unsigned int *s) +{ + int t1 = huf_tbl_noESC[max - 1]; + /* No ESC-words */ + const unsigned int xlen = ht[t1].xlen; + uint32_t const* table = (t1 == 2) ? &table23[0] : &table56[0]; + unsigned int sum = 0, sum2; + + do { + unsigned int const x0 = *ix++; + unsigned int const x1 = *ix++; + sum += table[ x0 * xlen + x1 ]; + } while (ix < end); + + sum2 = sum & 0xffffu; + sum >>= 16u; + + if (sum > sum2) { + sum = sum2; + t1++; + } + + *s += sum; + return t1; +} + + +inline static int +count_bit_noESC_from3(const int *ix, const int *end, int max, unsigned int * s) +{ + int t1 = huf_tbl_noESC[max - 1]; + /* No ESC-words */ + unsigned int sum1 = 0; + unsigned int sum2 = 0; + unsigned int sum3 = 0; + const unsigned int xlen = ht[t1].xlen; + const uint8_t *const hlen1 = ht[t1].hlen; + const uint8_t *const hlen2 = ht[t1 + 1].hlen; + const uint8_t *const hlen3 = ht[t1 + 2].hlen; + int t; + + do { + unsigned int x0 = *ix++; + unsigned int x1 = *ix++; + unsigned int x = x0 * xlen + x1; + sum1 += hlen1[x]; + sum2 += hlen2[x]; + sum3 += hlen3[x]; + } while (ix < end); + + t = t1; + if (sum1 > sum2) { + sum1 = sum2; + t++; + } + if (sum1 > sum3) { + sum1 = sum3; + t = t1 + 2; + } + *s += sum1; + + return t; +} + + +/*************************************************************************/ +/* choose table */ +/*************************************************************************/ + +/* + Choose the Huffman table that will encode ix[begin..end] with + the fewest bits. + + Note: This code contains knowledge about the sizes and characteristics + of the Huffman tables as defined in the IS (Table B.7), and will not work + with any arbitrary tables. +*/ +static int count_bit_null(const int* ix, const int* end, int max, unsigned int* s) +{ + (void) ix; + (void) end; + (void) max; + (void) s; + return 0; +} + +typedef int (*count_fnc)(const int* ix, const int* end, int max, unsigned int* s); + +static const count_fnc count_fncs[] = +{ &count_bit_null +, &count_bit_noESC +, &count_bit_noESC_from2 +, &count_bit_noESC_from2 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +}; + +static int +choose_table_nonMMX(const int *ix, const int *const end, int *const _s) +{ + unsigned int* s = (unsigned int*)_s; + unsigned int max; + int choice, choice2; + max = ix_max(ix, end); + + if (max <= 15) { + return count_fncs[max](ix, end, max, s); + } + /* try tables with linbits */ + if (max > IXMAX_VAL) { + *s = LARGE_BITS; + return -1; + } + max -= 15u; + for (choice2 = 24; choice2 < 32; choice2++) { + if (ht[choice2].linmax >= max) { + break; + } + } + + for (choice = choice2 - 8; choice < 24; choice++) { + if (ht[choice].linmax >= max) { + break; + } + } + return count_bit_ESC(ix, end, choice, choice2, s); +} + + + +/*************************************************************************/ +/* count_bit */ +/*************************************************************************/ +int +noquant_count_bits(lame_internal_flags const *const gfc, + gr_info * const gi, calc_noise_data * prev_noise) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int bits = 0; + int i, a1, a2; + int const *const ix = gi->l3_enc; + + i = Min(576, ((gi->max_nonzero_coeff + 2) >> 1) << 1); + + if (prev_noise) + prev_noise->sfb_count1 = 0; + + /* Determine count1 region */ + for (; i > 1; i -= 2) + if (ix[i - 1] | ix[i - 2]) + break; + gi->count1 = i; + + /* Determines the number of bits to encode the quadruples. */ + a1 = a2 = 0; + for (; i > 3; i -= 4) { + int x4 = ix[i-4]; + int x3 = ix[i-3]; + int x2 = ix[i-2]; + int x1 = ix[i-1]; + int p; + /* hack to check if all values <= 1 */ + if ((unsigned int) (x4 | x3 | x2 | x1) > 1) + break; + + p = ((x4 * 2 + x3) * 2 + x2) * 2 + x1; + a1 += t32l[p]; + a2 += t33l[p]; + } + + bits = a1; + gi->count1table_select = 0; + if (a1 > a2) { + bits = a2; + gi->count1table_select = 1; + } + + gi->count1bits = bits; + gi->big_values = i; + if (i == 0) + return bits; + + if (gi->block_type == SHORT_TYPE) { + a1 = 3 * gfc->scalefac_band.s[3]; + if (a1 > gi->big_values) + a1 = gi->big_values; + a2 = gi->big_values; + + } + else if (gi->block_type == NORM_TYPE) { + assert(i <= 576); /* bv_scf has 576 entries (0..575) */ + a1 = gi->region0_count = gfc->sv_qnt.bv_scf[i - 2]; + a2 = gi->region1_count = gfc->sv_qnt.bv_scf[i - 1]; + + assert(a1 + a2 + 2 < SBPSY_l); + a2 = gfc->scalefac_band.l[a1 + a2 + 2]; + a1 = gfc->scalefac_band.l[a1 + 1]; + if (a2 < i) + gi->table_select[2] = gfc->choose_table(ix + a2, ix + i, &bits); + + } + else { + gi->region0_count = 7; + /*gi->region1_count = SBPSY_l - 7 - 1; */ + gi->region1_count = SBMAX_l - 1 - 7 - 1; + a1 = gfc->scalefac_band.l[7 + 1]; + a2 = i; + if (a1 > a2) { + a1 = a2; + } + } + + + /* have to allow for the case when bigvalues < region0 < region1 */ + /* (and region0, region1 are ignored) */ + a1 = Min(a1, i); + a2 = Min(a2, i); + + assert(a1 >= 0); + assert(a2 >= 0); + + /* Count the number of bits necessary to code the bigvalues region. */ + if (0 < a1) + gi->table_select[0] = gfc->choose_table(ix, ix + a1, &bits); + if (a1 < a2) + gi->table_select[1] = gfc->choose_table(ix + a1, ix + a2, &bits); + if (cfg->use_best_huffman == 2) { + gi->part2_3_length = bits; + best_huffman_divide(gfc, gi); + bits = gi->part2_3_length; + } + + + if (prev_noise) { + if (gi->block_type == NORM_TYPE) { + int sfb = 0; + while (gfc->scalefac_band.l[sfb] < gi->big_values) { + sfb++; + } + prev_noise->sfb_count1 = sfb; + } + } + + return bits; +} + +int +count_bits(lame_internal_flags const *const gfc, + const FLOAT * const xr, gr_info * const gi, calc_noise_data * prev_noise) +{ + int *const ix = gi->l3_enc; + + /* since quantize_xrpow uses table lookup, we need to check this first: */ + FLOAT const w = (IXMAX_VAL) / IPOW20(gi->global_gain); + + if (gi->xrpow_max > w) + return LARGE_BITS; + + quantize_xrpow(xr, ix, IPOW20(gi->global_gain), gi, prev_noise); + + if (gfc->sv_qnt.substep_shaping & 2) { + int sfb, j = 0; + /* 0.634521682242439 = 0.5946*2**(.5*0.1875) */ + int const gain = gi->global_gain + gi->scalefac_scale; + const FLOAT roundfac = 0.634521682242439 / IPOW20(gain); + for (sfb = 0; sfb < gi->sfbmax; sfb++) { + int const width = gi->width[sfb]; + assert(width >= 0); + if (!gfc->sv_qnt.pseudohalf[sfb]) { + j += width; + } + else { + int k; + for (k = j, j += width; k < j; ++k) { + ix[k] = (xr[k] >= roundfac) ? ix[k] : 0; + } + } + } + } + return noquant_count_bits(gfc, gi, prev_noise); +} + +/*********************************************************************** + re-calculate the best scalefac_compress using scfsi + the saved bits are kept in the bit reservoir. + **********************************************************************/ + + +inline static void +recalc_divide_init(const lame_internal_flags * const gfc, + gr_info const *cod_info, + int const *const ix, int r01_bits[], int r01_div[], int r0_tbl[], int r1_tbl[]) +{ + int r0, r1, bigv, r0t, r1t, bits; + + bigv = cod_info->big_values; + + for (r0 = 0; r0 <= 7 + 15; r0++) { + r01_bits[r0] = LARGE_BITS; + } + + for (r0 = 0; r0 < 16; r0++) { + int const a1 = gfc->scalefac_band.l[r0 + 1]; + int r0bits; + if (a1 >= bigv) + break; + r0bits = 0; + r0t = gfc->choose_table(ix, ix + a1, &r0bits); + + for (r1 = 0; r1 < 8; r1++) { + int const a2 = gfc->scalefac_band.l[r0 + r1 + 2]; + if (a2 >= bigv) + break; + + bits = r0bits; + r1t = gfc->choose_table(ix + a1, ix + a2, &bits); + if (r01_bits[r0 + r1] > bits) { + r01_bits[r0 + r1] = bits; + r01_div[r0 + r1] = r0; + r0_tbl[r0 + r1] = r0t; + r1_tbl[r0 + r1] = r1t; + } + } + } +} + +inline static void +recalc_divide_sub(const lame_internal_flags * const gfc, + const gr_info * cod_info2, + gr_info * const gi, + const int *const ix, + const int r01_bits[], const int r01_div[], const int r0_tbl[], const int r1_tbl[]) +{ + int bits, r2, a2, bigv, r2t; + + bigv = cod_info2->big_values; + + for (r2 = 2; r2 < SBMAX_l + 1; r2++) { + a2 = gfc->scalefac_band.l[r2]; + if (a2 >= bigv) + break; + + bits = r01_bits[r2 - 2] + cod_info2->count1bits; + if (gi->part2_3_length <= bits) + break; + + r2t = gfc->choose_table(ix + a2, ix + bigv, &bits); + if (gi->part2_3_length <= bits) + continue; + + memcpy(gi, cod_info2, sizeof(gr_info)); + gi->part2_3_length = bits; + gi->region0_count = r01_div[r2 - 2]; + gi->region1_count = r2 - 2 - r01_div[r2 - 2]; + gi->table_select[0] = r0_tbl[r2 - 2]; + gi->table_select[1] = r1_tbl[r2 - 2]; + gi->table_select[2] = r2t; + } +} + + + + +void +best_huffman_divide(const lame_internal_flags * const gfc, gr_info * const gi) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int i, a1, a2; + gr_info cod_info2; + int const *const ix = gi->l3_enc; + + int r01_bits[7 + 15 + 1]; + int r01_div[7 + 15 + 1]; + int r0_tbl[7 + 15 + 1]; + int r1_tbl[7 + 15 + 1]; + + + /* SHORT BLOCK stuff fails for MPEG2 */ + if (gi->block_type == SHORT_TYPE && cfg->mode_gr == 1) + return; + + + memcpy(&cod_info2, gi, sizeof(gr_info)); + if (gi->block_type == NORM_TYPE) { + recalc_divide_init(gfc, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + recalc_divide_sub(gfc, &cod_info2, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + } + + i = cod_info2.big_values; + if (i == 0 || (unsigned int) (ix[i - 2] | ix[i - 1]) > 1) + return; + + i = gi->count1 + 2; + if (i > 576) + return; + + /* Determines the number of bits to encode the quadruples. */ + memcpy(&cod_info2, gi, sizeof(gr_info)); + cod_info2.count1 = i; + a1 = a2 = 0; + + assert(i <= 576); + + for (; i > cod_info2.big_values; i -= 4) { + int const p = ((ix[i - 4] * 2 + ix[i - 3]) * 2 + ix[i - 2]) * 2 + ix[i - 1]; + a1 += t32l[p]; + a2 += t33l[p]; + } + cod_info2.big_values = i; + + cod_info2.count1table_select = 0; + if (a1 > a2) { + a1 = a2; + cod_info2.count1table_select = 1; + } + + cod_info2.count1bits = a1; + + if (cod_info2.block_type == NORM_TYPE) + recalc_divide_sub(gfc, &cod_info2, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + else { + /* Count the number of bits necessary to code the bigvalues region. */ + cod_info2.part2_3_length = a1; + a1 = gfc->scalefac_band.l[7 + 1]; + if (a1 > i) { + a1 = i; + } + if (a1 > 0) + cod_info2.table_select[0] = + gfc->choose_table(ix, ix + a1, (int *) &cod_info2.part2_3_length); + if (i > a1) + cod_info2.table_select[1] = + gfc->choose_table(ix + a1, ix + i, (int *) &cod_info2.part2_3_length); + if (gi->part2_3_length > cod_info2.part2_3_length) + memcpy(gi, &cod_info2, sizeof(gr_info)); + } +} + +static const int slen1_n[16] = { 1, 1, 1, 1, 8, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16 }; +static const int slen2_n[16] = { 1, 2, 4, 8, 1, 2, 4, 8, 2, 4, 8, 2, 4, 8, 4, 8 }; +const int slen1_tab[16] = { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }; +const int slen2_tab[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 }; + +static void +scfsi_calc(int ch, III_side_info_t * l3_side) +{ + unsigned int i; + int s1, s2, c1, c2; + int sfb; + gr_info *const gi = &l3_side->tt[1][ch]; + gr_info const *const g0 = &l3_side->tt[0][ch]; + + for (i = 0; i < (sizeof(scfsi_band) / sizeof(int)) - 1; i++) { + for (sfb = scfsi_band[i]; sfb < scfsi_band[i + 1]; sfb++) { + if (g0->scalefac[sfb] != gi->scalefac[sfb] + && gi->scalefac[sfb] >= 0) + break; + } + if (sfb == scfsi_band[i + 1]) { + for (sfb = scfsi_band[i]; sfb < scfsi_band[i + 1]; sfb++) { + gi->scalefac[sfb] = -1; + } + l3_side->scfsi[ch][i] = 1; + } + } + + s1 = c1 = 0; + for (sfb = 0; sfb < 11; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; + c1++; + if (s1 < gi->scalefac[sfb]) + s1 = gi->scalefac[sfb]; + } + + s2 = c2 = 0; + for (; sfb < SBPSY_l; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; + c2++; + if (s2 < gi->scalefac[sfb]) + s2 = gi->scalefac[sfb]; + } + + for (i = 0; i < 16; i++) { + if (s1 < slen1_n[i] && s2 < slen2_n[i]) { + int const c = slen1_tab[i] * c1 + slen2_tab[i] * c2; + if (gi->part2_length > c) { + gi->part2_length = c; + gi->scalefac_compress = (int)i; + } + } + } +} + +/* +Find the optimal way to store the scalefactors. +Only call this routine after final scalefactors have been +chosen and the channel/granule will not be re-encoded. + */ +void +best_scalefac_store(const lame_internal_flags * gfc, + const int gr, const int ch, III_side_info_t * const l3_side) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + /* use scalefac_scale if we can */ + gr_info *const gi = &l3_side->tt[gr][ch]; + int sfb, i, j, l; + int recalc = 0; + + /* remove scalefacs from bands with ix=0. This idea comes + * from the AAC ISO docs. added mt 3/00 */ + /* check if l3_enc=0 */ + j = 0; + for (sfb = 0; sfb < gi->sfbmax; sfb++) { + int const width = gi->width[sfb]; + assert(width >= 0); + for (l = j, j += width; l < j; ++l) { + if (gi->l3_enc[l] != 0) + break; + } + if (l == j) + gi->scalefac[sfb] = recalc = -2; /* anything goes. */ + /* only best_scalefac_store and calc_scfsi + * know--and only they should know--about the magic number -2. + */ + } + + if (!gi->scalefac_scale && !gi->preflag) { + int s = 0; + for (sfb = 0; sfb < gi->sfbmax; sfb++) + if (gi->scalefac[sfb] > 0) + s |= gi->scalefac[sfb]; + + if (!(s & 1) && s != 0) { + for (sfb = 0; sfb < gi->sfbmax; sfb++) + if (gi->scalefac[sfb] > 0) + gi->scalefac[sfb] >>= 1; + + gi->scalefac_scale = recalc = 1; + } + } + + if (!gi->preflag && gi->block_type != SHORT_TYPE && cfg->mode_gr == 2) { + for (sfb = 11; sfb < SBPSY_l; sfb++) + if (gi->scalefac[sfb] < pretab[sfb] && gi->scalefac[sfb] != -2) + break; + if (sfb == SBPSY_l) { + for (sfb = 11; sfb < SBPSY_l; sfb++) + if (gi->scalefac[sfb] > 0) + gi->scalefac[sfb] -= pretab[sfb]; + + gi->preflag = recalc = 1; + } + } + + for (i = 0; i < 4; i++) + l3_side->scfsi[ch][i] = 0; + + if (cfg->mode_gr == 2 && gr == 1 + && l3_side->tt[0][ch].block_type != SHORT_TYPE + && l3_side->tt[1][ch].block_type != SHORT_TYPE) { + scfsi_calc(ch, l3_side); + recalc = 0; + } + for (sfb = 0; sfb < gi->sfbmax; sfb++) { + if (gi->scalefac[sfb] == -2) { + gi->scalefac[sfb] = 0; /* if anything goes, then 0 is a good choice */ + } + } + if (recalc) { + (void) scale_bitcount(gfc, gi); + } +} + + +#ifndef NDEBUG +static int +all_scalefactors_not_negative(int const *scalefac, int n) +{ + int i; + for (i = 0; i < n; ++i) { + if (scalefac[i] < 0) + return 0; + } + return 1; +} +#endif + + +/* number of bits used to encode scalefacs */ + +/* 18*slen1_tab[i] + 18*slen2_tab[i] */ +static const int scale_short[16] = { + 0, 18, 36, 54, 54, 36, 54, 72, 54, 72, 90, 72, 90, 108, 108, 126 +}; + +/* 17*slen1_tab[i] + 18*slen2_tab[i] */ +static const int scale_mixed[16] = { + 0, 18, 36, 54, 51, 35, 53, 71, 52, 70, 88, 69, 87, 105, 104, 122 +}; + +/* 11*slen1_tab[i] + 10*slen2_tab[i] */ +static const int scale_long[16] = { + 0, 10, 20, 30, 33, 21, 31, 41, 32, 42, 52, 43, 53, 63, 64, 74 +}; + + +/*************************************************************************/ +/* scale_bitcount */ +/*************************************************************************/ + +/* Also calculates the number of bits necessary to code the scalefactors. */ + +static int +mpeg1_scale_bitcount(const lame_internal_flags * gfc, gr_info * const cod_info) +{ + int k, sfb, max_slen1 = 0, max_slen2 = 0; + + /* maximum values */ + const int *tab; + int *const scalefac = cod_info->scalefac; + + (void) gfc; + assert(all_scalefactors_not_negative(scalefac, cod_info->sfbmax)); + + if (cod_info->block_type == SHORT_TYPE) { + tab = scale_short; + if (cod_info->mixed_block_flag) + tab = scale_mixed; + } + else { /* block_type == 1,2,or 3 */ + tab = scale_long; + if (!cod_info->preflag) { + for (sfb = 11; sfb < SBPSY_l; sfb++) + if (scalefac[sfb] < pretab[sfb]) + break; + + if (sfb == SBPSY_l) { + cod_info->preflag = 1; + for (sfb = 11; sfb < SBPSY_l; sfb++) + scalefac[sfb] -= pretab[sfb]; + } + } + } + + for (sfb = 0; sfb < cod_info->sfbdivide; sfb++) + if (max_slen1 < scalefac[sfb]) + max_slen1 = scalefac[sfb]; + + for (; sfb < cod_info->sfbmax; sfb++) + if (max_slen2 < scalefac[sfb]) + max_slen2 = scalefac[sfb]; + + /* from Takehiro TOMINAGA 10/99 + * loop over *all* posible values of scalefac_compress to find the + * one which uses the smallest number of bits. ISO would stop + * at first valid index */ + cod_info->part2_length = LARGE_BITS; + for (k = 0; k < 16; k++) { + if (max_slen1 < slen1_n[k] && max_slen2 < slen2_n[k] + && cod_info->part2_length > tab[k]) { + cod_info->part2_length = tab[k]; + cod_info->scalefac_compress = k; + } + } + return cod_info->part2_length == LARGE_BITS; +} + + + +/* + table of largest scalefactor values for MPEG2 +*/ +static const int max_range_sfac_tab[6][4] = { + {15, 15, 7, 7}, + {15, 15, 7, 0}, + {7, 3, 0, 0}, + {15, 31, 31, 0}, + {7, 7, 7, 0}, + {3, 3, 0, 0} +}; + + + + +/*************************************************************************/ +/* scale_bitcount_lsf */ +/*************************************************************************/ + +/* Also counts the number of bits to encode the scalefacs but for MPEG 2 */ +/* Lower sampling frequencies (24, 22.05 and 16 kHz.) */ + +/* This is reverse-engineered from section 2.4.3.2 of the MPEG2 IS, */ +/* "Audio Decoding Layer III" */ + +static int +mpeg2_scale_bitcount(const lame_internal_flags * gfc, gr_info * const cod_info) +{ + int table_number, row_in_table, partition, nr_sfb, window, over; + int i, sfb, max_sfac[4]; + const int *partition_table; + int const *const scalefac = cod_info->scalefac; + + /* + Set partition table. Note that should try to use table one, + but do not yet... + */ + if (cod_info->preflag) + table_number = 2; + else + table_number = 0; + + for (i = 0; i < 4; i++) + max_sfac[i] = 0; + + if (cod_info->block_type == SHORT_TYPE) { + row_in_table = 1; + partition_table = &nr_of_sfb_block[table_number][row_in_table][0]; + for (sfb = 0, partition = 0; partition < 4; partition++) { + nr_sfb = partition_table[partition] / 3; + for (i = 0; i < nr_sfb; i++, sfb++) + for (window = 0; window < 3; window++) + if (scalefac[sfb * 3 + window] > max_sfac[partition]) + max_sfac[partition] = scalefac[sfb * 3 + window]; + } + } + else { + row_in_table = 0; + partition_table = &nr_of_sfb_block[table_number][row_in_table][0]; + for (sfb = 0, partition = 0; partition < 4; partition++) { + nr_sfb = partition_table[partition]; + for (i = 0; i < nr_sfb; i++, sfb++) + if (scalefac[sfb] > max_sfac[partition]) + max_sfac[partition] = scalefac[sfb]; + } + } + + for (over = 0, partition = 0; partition < 4; partition++) { + if (max_sfac[partition] > max_range_sfac_tab[table_number][partition]) + over++; + } + if (!over) { + /* + Since no bands have been over-amplified, we can set scalefac_compress + and slen[] for the formatter + */ + static const int log2tab[] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; + + int slen1, slen2, slen3, slen4; + + cod_info->sfb_partition_table = nr_of_sfb_block[table_number][row_in_table]; + for (partition = 0; partition < 4; partition++) + cod_info->slen[partition] = log2tab[max_sfac[partition]]; + + /* set scalefac_compress */ + slen1 = cod_info->slen[0]; + slen2 = cod_info->slen[1]; + slen3 = cod_info->slen[2]; + slen4 = cod_info->slen[3]; + + switch (table_number) { + case 0: + cod_info->scalefac_compress = (((slen1 * 5) + slen2) << 4) + + (slen3 << 2) + + slen4; + break; + + case 1: + cod_info->scalefac_compress = 400 + (((slen1 * 5) + slen2) << 2) + + slen3; + break; + + case 2: + cod_info->scalefac_compress = 500 + (slen1 * 3) + slen2; + break; + + default: + ERRORF(gfc, "intensity stereo not implemented yet\n"); + break; + } + } +#ifdef DEBUG + if (over) + ERRORF(gfc, "---WARNING !! Amplification of some bands over limits\n"); +#endif + if (!over) { + assert(cod_info->sfb_partition_table); + cod_info->part2_length = 0; + for (partition = 0; partition < 4; partition++) + cod_info->part2_length += + cod_info->slen[partition] * cod_info->sfb_partition_table[partition]; + } + return over; +} + + +int +scale_bitcount(const lame_internal_flags * gfc, gr_info * cod_info) +{ + if (gfc->cfg.mode_gr == 2) { + return mpeg1_scale_bitcount(gfc, cod_info); + } + else { + return mpeg2_scale_bitcount(gfc, cod_info); + } +} + + +#ifdef MMX_choose_table +extern int choose_table_MMX(const int *ix, const int *const end, int *const s); +#endif + +void +huffman_init(lame_internal_flags * const gfc) +{ + int i; + + gfc->choose_table = choose_table_nonMMX; + +#ifdef MMX_choose_table + if (gfc->CPU_features.MMX) { + gfc->choose_table = choose_table_MMX; + } +#endif + + for (i = 2; i <= 576; i += 2) { + int scfb_anz = 0, bv_index; + while (gfc->scalefac_band.l[++scfb_anz] < i); + + bv_index = subdv_table[scfb_anz].region0_count; + while (gfc->scalefac_band.l[bv_index + 1] > i) + bv_index--; + + if (bv_index < 0) { + /* this is an indication that everything is going to + be encoded as region0: bigvalues < region0 < region1 + so lets set region0, region1 to some value larger + than bigvalues */ + bv_index = subdv_table[scfb_anz].region0_count; + } + + gfc->sv_qnt.bv_scf[i - 2] = bv_index; + + bv_index = subdv_table[scfb_anz].region1_count; + while (gfc->scalefac_band.l[bv_index + gfc->sv_qnt.bv_scf[i - 2] + 2] > i) + bv_index--; + + if (bv_index < 0) { + bv_index = subdv_table[scfb_anz].region1_count; + } + + gfc->sv_qnt.bv_scf[i - 1] = bv_index; + } +} diff --git a/pkg/lame/clame/util.c b/pkg/lame/clame/util.c new file mode 100644 index 0000000..43b457c --- /dev/null +++ b/pkg/lame/clame/util.c @@ -0,0 +1,1018 @@ +/* + * lame utility library source file + * + * Copyright (c) 1999 Albert L Faber + * Copyright (c) 2000-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: util.c,v 1.159 2017/09/06 15:07:30 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "tables.h" + +#define PRECOMPUTE +#if defined(__FreeBSD__) && !defined(__alpha__) +# include +#endif + + +/*********************************************************************** +* +* Global Function Definitions +* +***********************************************************************/ +/*empty and close mallocs in gfc */ + +void +free_id3tag(lame_internal_flags * const gfc) +{ + gfc->tag_spec.language[0] = 0; + if (gfc->tag_spec.title != 0) { + free(gfc->tag_spec.title); + gfc->tag_spec.title = 0; + } + if (gfc->tag_spec.artist != 0) { + free(gfc->tag_spec.artist); + gfc->tag_spec.artist = 0; + } + if (gfc->tag_spec.album != 0) { + free(gfc->tag_spec.album); + gfc->tag_spec.album = 0; + } + if (gfc->tag_spec.comment != 0) { + free(gfc->tag_spec.comment); + gfc->tag_spec.comment = 0; + } + + if (gfc->tag_spec.albumart != 0) { + free(gfc->tag_spec.albumart); + gfc->tag_spec.albumart = 0; + gfc->tag_spec.albumart_size = 0; + gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE; + } + if (gfc->tag_spec.v2_head != 0) { + FrameDataNode *node = gfc->tag_spec.v2_head; + do { + void *p = node->dsc.ptr.b; + void *q = node->txt.ptr.b; + void *r = node; + node = node->nxt; + free(p); + free(q); + free(r); + } while (node != 0); + gfc->tag_spec.v2_head = 0; + gfc->tag_spec.v2_tail = 0; + } +} + + +static void +free_global_data(lame_internal_flags * gfc) +{ + if (gfc && gfc->cd_psy) { + if (gfc->cd_psy->l.s3) { + /* XXX allocated in psymodel_init() */ + free(gfc->cd_psy->l.s3); + } + if (gfc->cd_psy->s.s3) { + /* XXX allocated in psymodel_init() */ + free(gfc->cd_psy->s.s3); + } + free(gfc->cd_psy); + gfc->cd_psy = 0; + } +} + + +void +freegfc(lame_internal_flags * const gfc) +{ /* bit stream structure */ + int i; + + if (gfc == 0) return; + + for (i = 0; i <= 2 * BPC; i++) + if (gfc->sv_enc.blackfilt[i] != NULL) { + free(gfc->sv_enc.blackfilt[i]); + gfc->sv_enc.blackfilt[i] = NULL; + } + if (gfc->sv_enc.inbuf_old[0]) { + free(gfc->sv_enc.inbuf_old[0]); + gfc->sv_enc.inbuf_old[0] = NULL; + } + if (gfc->sv_enc.inbuf_old[1]) { + free(gfc->sv_enc.inbuf_old[1]); + gfc->sv_enc.inbuf_old[1] = NULL; + } + + if (gfc->bs.buf != NULL) { + free(gfc->bs.buf); + gfc->bs.buf = NULL; + } + + if (gfc->VBR_seek_table.bag) { + free(gfc->VBR_seek_table.bag); + gfc->VBR_seek_table.bag = NULL; + gfc->VBR_seek_table.size = 0; + } + if (gfc->ATH) { + free(gfc->ATH); + } + if (gfc->sv_rpg.rgdata) { + free(gfc->sv_rpg.rgdata); + } + if (gfc->sv_enc.in_buffer_0) { + free(gfc->sv_enc.in_buffer_0); + } + if (gfc->sv_enc.in_buffer_1) { + free(gfc->sv_enc.in_buffer_1); + } + free_id3tag(gfc); + +#ifdef DECODE_ON_THE_FLY + if (gfc->hip) { + hip_decode_exit(gfc->hip); + gfc->hip = 0; + } +#endif + + free_global_data(gfc); + + free(gfc); +} + +void +calloc_aligned(aligned_pointer_t * ptr, unsigned int size, unsigned int bytes) +{ + if (ptr) { + if (!ptr->pointer) { + ptr->pointer = malloc(size + bytes); + if (ptr->pointer != 0) { + memset(ptr->pointer, 0, size + bytes); + if (bytes > 0) { + ptr->aligned = (void *) ((((size_t) ptr->pointer + bytes - 1) / bytes) * bytes); + } + else { + ptr->aligned = ptr->pointer; + } + } + else { + ptr->aligned = 0; + } + } + } +} + +void +free_aligned(aligned_pointer_t * ptr) +{ + if (ptr) { + if (ptr->pointer) { + free(ptr->pointer); + ptr->pointer = 0; + ptr->aligned = 0; + } + } +} + +/*those ATH formulas are returning +their minimum value for input = -1*/ + +static FLOAT +ATHformula_GB(FLOAT f, FLOAT value, FLOAT f_min, FLOAT f_max) +{ + /* from Painter & Spanias + modified by Gabriel Bouvigne to better fit the reality + ath = 3.640 * pow(f,-0.8) + - 6.800 * exp(-0.6*pow(f-3.4,2.0)) + + 6.000 * exp(-0.15*pow(f-8.7,2.0)) + + 0.6* 0.001 * pow(f,4.0); + + + In the past LAME was using the Painter &Spanias formula. + But we had some recurrent problems with HF content. + We measured real ATH values, and found the older formula + to be inacurate in the higher part. So we made this new + formula and this solved most of HF problematic testcases. + The tradeoff is that in VBR mode it increases a lot the + bitrate. */ + + +/*this curve can be udjusted according to the VBR scale: +it adjusts from something close to Painter & Spanias +on V9 up to Bouvigne's formula for V0. This way the VBR +bitrate is more balanced according to the -V value.*/ + + FLOAT ath; + + /* the following Hack allows to ask for the lowest value */ + if (f < -.3) + f = 3410; + + f /= 1000; /* convert to khz */ + f = Max(f_min, f); + f = Min(f_max, f); + + ath = 3.640 * pow(f, -0.8) + - 6.800 * exp(-0.6 * pow(f - 3.4, 2.0)) + + 6.000 * exp(-0.15 * pow(f - 8.7, 2.0)) + + (0.6 + 0.04 * value) * 0.001 * pow(f, 4.0); + return ath; +} + + + +FLOAT +ATHformula(SessionConfig_t const *cfg, FLOAT f) +{ + FLOAT ath; + switch (cfg->ATHtype) { + case 0: + ath = ATHformula_GB(f, 9, 0.1f, 24.0f); + break; + case 1: + ath = ATHformula_GB(f, -1, 0.1f, 24.0f); /*over sensitive, should probably be removed */ + break; + case 2: + ath = ATHformula_GB(f, 0, 0.1f, 24.0f); + break; + case 3: + ath = ATHformula_GB(f, 1, 0.1f, 24.0f) + 6; /*modification of GB formula by Roel */ + break; + case 4: + ath = ATHformula_GB(f, cfg->ATHcurve, 0.1f, 24.0f); + break; + case 5: + ath = ATHformula_GB(f, cfg->ATHcurve, 3.41f, 16.1f); + break; + default: + ath = ATHformula_GB(f, 0, 0.1f, 24.0f); + break; + } + return ath; +} + +/* see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 */ +FLOAT +freq2bark(FLOAT freq) +{ + /* input: freq in hz output: barks */ + if (freq < 0) + freq = 0; + freq = freq * 0.001; + return 13.0 * atan(.76 * freq) + 3.5 * atan(freq * freq / (7.5 * 7.5)); +} + +#if 0 +extern FLOAT freq2cbw(FLOAT freq); + +/* see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 */ +FLOAT +freq2cbw(FLOAT freq) +{ + /* input: freq in hz output: critical band width */ + freq = freq * 0.001; + return 25 + 75 * pow(1 + 1.4 * (freq * freq), 0.69); +} + +#endif + + + + +#define ABS(A) (((A)>0) ? (A) : -(A)) + +int +FindNearestBitrate(int bRate, /* legal rates from 8 to 320 */ + int version, int samplerate) +{ /* MPEG-1 or MPEG-2 LSF */ + int bitrate; + int i; + + if (samplerate < 16000) + version = 2; + + bitrate = bitrate_table[version][1]; + + for (i = 2; i <= 14; i++) { + if (bitrate_table[version][i] > 0) { + if (ABS(bitrate_table[version][i] - bRate) < ABS(bitrate - bRate)) + bitrate = bitrate_table[version][i]; + } + } + return bitrate; +} + + + + + +#ifndef Min +#define Min(A, B) ((A) < (B) ? (A) : (B)) +#endif +#ifndef Max +#define Max(A, B) ((A) > (B) ? (A) : (B)) +#endif + + +/* Used to find table index when + * we need bitrate-based values + * determined using tables + * + * bitrate in kbps + * + * Gabriel Bouvigne 2002-11-03 + */ +int +nearestBitrateFullIndex(uint16_t bitrate) +{ + /* borrowed from DM abr presets */ + + const int full_bitrate_table[] = + { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }; + + + int lower_range = 0, lower_range_kbps = 0, upper_range = 0, upper_range_kbps = 0; + + + int b; + + + /* We assume specified bitrate will be 320kbps */ + upper_range_kbps = full_bitrate_table[16]; + upper_range = 16; + lower_range_kbps = full_bitrate_table[16]; + lower_range = 16; + + /* Determine which significant bitrates the value specified falls between, + * if loop ends without breaking then we were correct above that the value was 320 + */ + for (b = 0; b < 16; b++) { + if ((Max(bitrate, full_bitrate_table[b + 1])) != bitrate) { + upper_range_kbps = full_bitrate_table[b + 1]; + upper_range = b + 1; + lower_range_kbps = full_bitrate_table[b]; + lower_range = (b); + break; /* We found upper range */ + } + } + + /* Determine which range the value specified is closer to */ + if ((upper_range_kbps - bitrate) > (bitrate - lower_range_kbps)) { + return lower_range; + } + return upper_range; +} + + + + + +/* map frequency to a valid MP3 sample frequency + * + * Robert Hegemann 2000-07-01 + */ +int +map2MP3Frequency(int freq) +{ + if (freq <= 8000) + return 8000; + if (freq <= 11025) + return 11025; + if (freq <= 12000) + return 12000; + if (freq <= 16000) + return 16000; + if (freq <= 22050) + return 22050; + if (freq <= 24000) + return 24000; + if (freq <= 32000) + return 32000; + if (freq <= 44100) + return 44100; + + return 48000; +} + +int +BitrateIndex(int bRate, /* legal rates from 32 to 448 kbps */ + int version, /* MPEG-1 or MPEG-2/2.5 LSF */ + int samplerate) +{ /* convert bitrate in kbps to index */ + int i; + if (samplerate < 16000) + version = 2; + for (i = 0; i <= 14; i++) { + if (bitrate_table[version][i] > 0) { + if (bitrate_table[version][i] == bRate) { + return i; + } + } + } + return -1; +} + +/* convert samp freq in Hz to index */ + +int +SmpFrqIndex(int sample_freq, int *const version) +{ + switch (sample_freq) { + case 44100: + *version = 1; + return 0; + case 48000: + *version = 1; + return 1; + case 32000: + *version = 1; + return 2; + case 22050: + *version = 0; + return 0; + case 24000: + *version = 0; + return 1; + case 16000: + *version = 0; + return 2; + case 11025: + *version = 0; + return 0; + case 12000: + *version = 0; + return 1; + case 8000: + *version = 0; + return 2; + default: + *version = 0; + return -1; + } +} + + +/***************************************************************************** +* +* End of bit_stream.c package +* +*****************************************************************************/ + + + + + + + + + + +/* resampling via FIR filter, blackman window */ +inline static FLOAT +blackman(FLOAT x, FLOAT fcn, int l) +{ + /* This algorithm from: + SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C + S.D. Stearns and R.A. David, Prentice-Hall, 1992 + */ + FLOAT bkwn, x2; + FLOAT const wcn = (PI * fcn); + + x /= l; + if (x < 0) + x = 0; + if (x > 1) + x = 1; + x2 = x - .5; + + bkwn = 0.42 - 0.5 * cos(2 * x * PI) + 0.08 * cos(4 * x * PI); + if (fabs(x2) < 1e-9) + return wcn / PI; + else + return (bkwn * sin(l * wcn * x2) / (PI * l * x2)); + + +} + + + + +/* gcd - greatest common divisor */ +/* Joint work of Euclid and M. Hendry */ + +static int +gcd(int i, int j) +{ + /* assert ( i > 0 && j > 0 ); */ + return j ? gcd(j, i % j) : i; +} + + + +static int +fill_buffer_resample(lame_internal_flags * gfc, + sample_t * outbuf, + int desired_len, sample_t const *inbuf, int len, int *num_used, int ch) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *esv = &gfc->sv_enc; + double resample_ratio = (double)cfg->samplerate_in / (double)cfg->samplerate_out; + int BLACKSIZE; + FLOAT offset, xvalue; + int i, j = 0, k; + int filter_l; + FLOAT fcn, intratio; + FLOAT *inbuf_old; + int bpc; /* number of convolution functions to pre-compute */ + bpc = cfg->samplerate_out / gcd(cfg->samplerate_out, cfg->samplerate_in); + if (bpc > BPC) + bpc = BPC; + + intratio = (fabs(resample_ratio - floor(.5 + resample_ratio)) < FLT_EPSILON); + fcn = 1.00 / resample_ratio; + if (fcn > 1.00) + fcn = 1.00; + filter_l = 31; /* must be odd */ + filter_l += intratio; /* unless resample_ratio=int, it must be even */ + + + BLACKSIZE = filter_l + 1; /* size of data needed for FIR */ + + if (gfc->fill_buffer_resample_init == 0) { + esv->inbuf_old[0] = lame_calloc(sample_t, BLACKSIZE); + esv->inbuf_old[1] = lame_calloc(sample_t, BLACKSIZE); + for (i = 0; i <= 2 * bpc; ++i) + esv->blackfilt[i] = lame_calloc(sample_t, BLACKSIZE); + + esv->itime[0] = 0; + esv->itime[1] = 0; + + /* precompute blackman filter coefficients */ + for (j = 0; j <= 2 * bpc; j++) { + FLOAT sum = 0.; + offset = (j - bpc) / (2. * bpc); + for (i = 0; i <= filter_l; i++) + sum += esv->blackfilt[j][i] = blackman(i - offset, fcn, filter_l); + for (i = 0; i <= filter_l; i++) + esv->blackfilt[j][i] /= sum; + } + gfc->fill_buffer_resample_init = 1; + } + + inbuf_old = esv->inbuf_old[ch]; + + /* time of j'th element in inbuf = itime + j/ifreq; */ + /* time of k'th element in outbuf = j/ofreq */ + for (k = 0; k < desired_len; k++) { + double time0 = k * resample_ratio; /* time of k'th output sample */ + int joff; + + j = floor(time0 - esv->itime[ch]); + + /* check if we need more input data */ + if ((filter_l + j - filter_l / 2) >= len) + break; + + /* blackman filter. by default, window centered at j+.5(filter_l%2) */ + /* but we want a window centered at time0. */ + offset = (time0 - esv->itime[ch] - (j + .5 * (filter_l % 2))); + assert(fabs(offset) <= .501); + + /* find the closest precomputed window for this offset: */ + joff = floor((offset * 2 * bpc) + bpc + .5); + + xvalue = 0.; + for (i = 0; i <= filter_l; ++i) { + int const j2 = i + j - filter_l / 2; + sample_t y; + assert(j2 < len); + assert(j2 + BLACKSIZE >= 0); + y = (j2 < 0) ? inbuf_old[BLACKSIZE + j2] : inbuf[j2]; +#ifdef PRECOMPUTE + xvalue += y * esv->blackfilt[joff][i]; +#else + xvalue += y * blackman(i - offset, fcn, filter_l); /* very slow! */ +#endif + } + outbuf[k] = xvalue; + } + + + /* k = number of samples added to outbuf */ + /* last k sample used data from [j-filter_l/2,j+filter_l-filter_l/2] */ + + /* how many samples of input data were used: */ + *num_used = Min(len, filter_l + j - filter_l / 2); + + /* adjust our input time counter. Incriment by the number of samples used, + * then normalize so that next output sample is at time 0, next + * input buffer is at time itime[ch] */ + esv->itime[ch] += *num_used - k * resample_ratio; + + /* save the last BLACKSIZE samples into the inbuf_old buffer */ + if (*num_used >= BLACKSIZE) { + for (i = 0; i < BLACKSIZE; i++) + inbuf_old[i] = inbuf[*num_used + i - BLACKSIZE]; + } + else { + /* shift in *num_used samples into inbuf_old */ + int const n_shift = BLACKSIZE - *num_used; /* number of samples to shift */ + + /* shift n_shift samples by *num_used, to make room for the + * num_used new samples */ + for (i = 0; i < n_shift; ++i) + inbuf_old[i] = inbuf_old[i + *num_used]; + + /* shift in the *num_used samples */ + for (j = 0; i < BLACKSIZE; ++i, ++j) + inbuf_old[i] = inbuf[j]; + + assert(j == *num_used); + } + return k; /* return the number samples created at the new samplerate */ +} + +int +isResamplingNecessary(SessionConfig_t const* cfg) +{ + int const l = cfg->samplerate_out * 0.9995f; + int const h = cfg->samplerate_out * 1.0005f; + return (cfg->samplerate_in < l) || (h < cfg->samplerate_in) ? 1 : 0; +} + +/* copy in new samples from in_buffer into mfbuf, with resampling + if necessary. n_in = number of samples from the input buffer that + were used. n_out = number of samples copied into mfbuf */ + +void +fill_buffer(lame_internal_flags * gfc, + sample_t * const mfbuf[2], sample_t const * const in_buffer[2], int nsamples, int *n_in, int *n_out) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int mf_size = gfc->sv_enc.mf_size; + int framesize = 576 * cfg->mode_gr; + int nout, ch = 0; + int nch = cfg->channels_out; + + /* copy in new samples into mfbuf, with resampling if necessary */ + if (isResamplingNecessary(cfg)) { + do { + nout = + fill_buffer_resample(gfc, &mfbuf[ch][mf_size], + framesize, in_buffer[ch], nsamples, n_in, ch); + } while (++ch < nch); + *n_out = nout; + } + else { + nout = Min(framesize, nsamples); + do { + memcpy(&mfbuf[ch][mf_size], &in_buffer[ch][0], nout * sizeof(mfbuf[0][0])); + } while (++ch < nch); + *n_out = nout; + *n_in = nout; + } +} + + + + + + + +/*********************************************************************** +* +* Message Output +* +***********************************************************************/ + +void +lame_report_def(const char *format, va_list args) +{ + (void) vfprintf(stderr, format, args); + fflush(stderr); /* an debug function should flush immediately */ +} + +void +lame_report_fnc(lame_report_function print_f, const char *format, ...) +{ + if (print_f) { + va_list args; + va_start(args, format); + print_f(format, args); + va_end(args); + } +} + + +void +lame_debugf(const lame_internal_flags* gfc, const char *format, ...) +{ + if (gfc && gfc->report_dbg) { + va_list args; + va_start(args, format); + gfc->report_dbg(format, args); + va_end(args); + } +} + + +void +lame_msgf(const lame_internal_flags* gfc, const char *format, ...) +{ + if (gfc && gfc->report_msg) { + va_list args; + va_start(args, format); + gfc->report_msg(format, args); + va_end(args); + } +} + + +void +lame_errorf(const lame_internal_flags* gfc, const char *format, ...) +{ + if (gfc && gfc->report_err) { + va_list args; + va_start(args, format); + gfc->report_err(format, args); + va_end(args); + } +} + + + +/*********************************************************************** + * + * routines to detect CPU specific features like 3DNow, MMX, SSE + * + * donated by Frank Klemm + * added Robert Hegemann 2000-10-10 + * + ***********************************************************************/ + +#ifdef HAVE_NASM +extern int has_MMX_nasm(void); +extern int has_3DNow_nasm(void); +extern int has_SSE_nasm(void); +extern int has_SSE2_nasm(void); +#endif + +int +has_MMX(void) +{ +#ifdef HAVE_NASM + return has_MMX_nasm(); +#else + return 0; /* don't know, assume not */ +#endif +} + +int +has_3DNow(void) +{ +#ifdef HAVE_NASM + return has_3DNow_nasm(); +#else + return 0; /* don't know, assume not */ +#endif +} + +int +has_SSE(void) +{ +#ifdef HAVE_NASM + return has_SSE_nasm(); +#else +#if defined( _M_X64 ) || defined( MIN_ARCH_SSE ) + return 1; +#else + return 0; /* don't know, assume not */ +#endif +#endif +} + +int +has_SSE2(void) +{ +#ifdef HAVE_NASM + return has_SSE2_nasm(); +#else +#if defined( _M_X64 ) || defined( MIN_ARCH_SSE ) + return 1; +#else + return 0; /* don't know, assume not */ +#endif +#endif +} + +void +disable_FPE(void) +{ +/* extremly system dependent stuff, move to a lib to make the code readable */ +/*==========================================================================*/ + + + + /* + * Disable floating point exceptions + */ + + + + +#if defined(__FreeBSD__) && !defined(__alpha__) + { + /* seet floating point mask to the Linux default */ + fp_except_t mask; + mask = fpgetmask(); + /* if bit is set, we get SIGFPE on that error! */ + fpsetmask(mask & ~(FP_X_INV | FP_X_DZ)); + /* DEBUGF("FreeBSD mask is 0x%x\n",mask); */ + } +#endif + +#if defined(__riscos__) && !defined(ABORTFP) + /* Disable FPE's under RISC OS */ + /* if bit is set, we disable trapping that error! */ + /* _FPE_IVO : invalid operation */ + /* _FPE_DVZ : divide by zero */ + /* _FPE_OFL : overflow */ + /* _FPE_UFL : underflow */ + /* _FPE_INX : inexact */ + DisableFPETraps(_FPE_IVO | _FPE_DVZ | _FPE_OFL); +#endif + + /* + * Debugging stuff + * The default is to ignore FPE's, unless compiled with -DABORTFP + * so add code below to ENABLE FPE's. + */ + +#if defined(ABORTFP) +#if defined(_MSC_VER) + { +#if 0 + /* rh 061207 + the following fix seems to be a workaround for a problem in the + parent process calling LAME. It would be better to fix the broken + application => code disabled. + */ + + /* set affinity to a single CPU. Fix for EAC/lame on SMP systems from + "Todd Richmond" */ + SYSTEM_INFO si; + GetSystemInfo(&si); + SetProcessAffinityMask(GetCurrentProcess(), si.dwActiveProcessorMask); +#endif +#include + unsigned int mask; + mask = _controlfp(0, 0); + mask &= ~(_EM_OVERFLOW | _EM_UNDERFLOW | _EM_ZERODIVIDE | _EM_INVALID); + mask = _controlfp(mask, _MCW_EM); + } +#elif defined(__CYGWIN__) +# define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) +# define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) + +# define _EM_INEXACT 0x00000020 /* inexact (precision) */ +# define _EM_UNDERFLOW 0x00000010 /* underflow */ +# define _EM_OVERFLOW 0x00000008 /* overflow */ +# define _EM_ZERODIVIDE 0x00000004 /* zero divide */ +# define _EM_INVALID 0x00000001 /* invalid */ + { + unsigned int mask; + _FPU_GETCW(mask); + /* Set the FPU control word to abort on most FPEs */ + mask &= ~(_EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID); + _FPU_SETCW(mask); + } +# elif defined(__linux__) + { + +# include +# ifndef _FPU_GETCW +# define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) +# endif +# ifndef _FPU_SETCW +# define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) +# endif + + /* + * Set the Linux mask to abort on most FPE's + * if bit is set, we _mask_ SIGFPE on that error! + * mask &= ~( _FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM ); + */ + + unsigned int mask; + _FPU_GETCW(mask); + mask &= ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM); + _FPU_SETCW(mask); + } +#endif +#endif /* ABORTFP */ +} + + + + + +#ifdef USE_FAST_LOG +/*********************************************************************** + * + * Fast Log Approximation for log2, used to approximate every other log + * (log10 and log) + * maximum absolute error for log10 is around 10-6 + * maximum *relative* error can be high when x is almost 1 because error/log10(x) tends toward x/e + * + * use it if typical RESULT values are > 1e-5 (for example if x>1.00001 or x<0.99999) + * or if the relative precision in the domain around 1 is not important (result in 1 is exact and 0) + * + ***********************************************************************/ + + +#define LOG2_SIZE (512) +#define LOG2_SIZE_L2 (9) + +static ieee754_float32_t log_table[LOG2_SIZE + 1]; + + + +void +init_log_table(void) +{ + int j; + static int init = 0; + + /* Range for log2(x) over [1,2[ is [0,1[ */ + assert((1 << LOG2_SIZE_L2) == LOG2_SIZE); + + if (!init) { + for (j = 0; j < LOG2_SIZE + 1; j++) + log_table[j] = log(1.0f + j / (ieee754_float32_t) LOG2_SIZE) / log(2.0f); + } + init = 1; +} + + + +ieee754_float32_t +fast_log2(ieee754_float32_t x) +{ + ieee754_float32_t log2val, partial; + union { + ieee754_float32_t f; + int i; + } fi; + int mantisse; + fi.f = x; + mantisse = fi.i & 0x7fffff; + log2val = ((fi.i >> 23) & 0xFF) - 0x7f; + partial = (mantisse & ((1 << (23 - LOG2_SIZE_L2)) - 1)); + partial *= 1.0f / ((1 << (23 - LOG2_SIZE_L2))); + + + mantisse >>= (23 - LOG2_SIZE_L2); + + /* log2val += log_table[mantisse]; without interpolation the results are not good */ + log2val += log_table[mantisse] * (1.0f - partial) + log_table[mantisse + 1] * partial; + + return log2val; +} + +#else /* Don't use FAST_LOG */ + + +void +init_log_table(void) +{ +} + + +#endif + +/* end of util.c */ diff --git a/pkg/lame/clame/util.h b/pkg/lame/clame/util.h new file mode 100644 index 0000000..13f0cd4 --- /dev/null +++ b/pkg/lame/clame/util.h @@ -0,0 +1,616 @@ +/* + * lame utility library include file + * + * Copyright (c) 1999 Albert L Faber + * Copyright (c) 2008 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_UTIL_H +#define LAME_UTIL_H + +#include "l3side.h" +#include "id3tag.h" +#include "lame_global_flags.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*********************************************************************** +* +* Global Definitions +* +***********************************************************************/ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifdef UINT_MAX +# define MAX_U_32_NUM UINT_MAX +#else +# define MAX_U_32_NUM 0xFFFFFFFF +#endif + +#ifndef PI +# ifdef M_PI +# define PI M_PI +# else +# define PI 3.14159265358979323846 +# endif +#endif + + +#ifdef M_LN2 +# define LOG2 M_LN2 +#else +# define LOG2 0.69314718055994530942 +#endif + +#ifdef M_LN10 +# define LOG10 M_LN10 +#else +# define LOG10 2.30258509299404568402 +#endif + + +#ifdef M_SQRT2 +# define SQRT2 M_SQRT2 +#else +# define SQRT2 1.41421356237309504880 +#endif + + +#define CRC16_POLYNOMIAL 0x8005 + +#define MAX_BITS_PER_CHANNEL 4095 +#define MAX_BITS_PER_GRANULE 7680 + +/* "bit_stream.h" Definitions */ +#define BUFFER_SIZE LAME_MAXMP3BUFFER + +#define Min(A, B) ((A) < (B) ? (A) : (B)) +#define Max(A, B) ((A) > (B) ? (A) : (B)) + +/* log/log10 approximations */ +#ifdef USE_FAST_LOG +#define FAST_LOG10(x) (fast_log2(x)*(LOG2/LOG10)) +#define FAST_LOG(x) (fast_log2(x)*LOG2) +#define FAST_LOG10_X(x,y) (fast_log2(x)*(LOG2/LOG10*(y))) +#define FAST_LOG_X(x,y) (fast_log2(x)*(LOG2*(y))) +#else +#define FAST_LOG10(x) log10(x) +#define FAST_LOG(x) log(x) +#define FAST_LOG10_X(x,y) (log10(x)*(y)) +#define FAST_LOG_X(x,y) (log(x)*(y)) +#endif + + + struct replaygain_data; +#ifndef replaygain_data_defined +#define replaygain_data_defined + typedef struct replaygain_data replaygain_t; +#endif + struct plotting_data; +#ifndef plotting_data_defined +#define plotting_data_defined + typedef struct plotting_data plotting_data; +#endif + +/*********************************************************************** +* +* Global Type Definitions +* +***********************************************************************/ + + typedef struct { + void *aligned; /* pointer to ie. 128 bit aligned memory */ + void *pointer; /* to use with malloc/free */ + } aligned_pointer_t; + + void calloc_aligned(aligned_pointer_t * ptr, unsigned int size, unsigned int bytes); + void free_aligned(aligned_pointer_t * ptr); + + + /* "bit_stream.h" Type Definitions */ + + typedef struct bit_stream_struc { + unsigned char *buf; /* bit stream buffer */ + int buf_size; /* size of buffer (in number of bytes) */ + int totbit; /* bit counter of bit stream */ + int buf_byte_idx; /* pointer to top byte in buffer */ + int buf_bit_idx; /* pointer to top bit of top byte in buffer */ + + /* format of file in rd mode (BINARY/ASCII) */ + } Bit_stream_struc; + + + + typedef struct { + int sum; /* what we have seen so far */ + int seen; /* how many frames we have seen in this chunk */ + int want; /* how many frames we want to collect into one chunk */ + int pos; /* actual position in our bag */ + int size; /* size of our bag */ + int *bag; /* pointer to our bag */ + unsigned int nVbrNumFrames; + unsigned long nBytesWritten; + /* VBR tag data */ + unsigned int TotalFrameSize; + } VBR_seek_info_t; + + + /** + * ATH related stuff, if something new ATH related has to be added, + * please plugg it here into the ATH_t struct + */ + typedef struct { + int use_adjust; /* method for the auto adjustment */ + FLOAT aa_sensitivity_p; /* factor for tuning the (sample power) + point below which adaptive threshold + of hearing adjustment occurs */ + FLOAT adjust_factor; /* lowering based on peak volume, 1 = no lowering */ + FLOAT adjust_limit; /* limit for dynamic ATH adjust */ + FLOAT decay; /* determined to lower x dB each second */ + FLOAT floor; /* lowest ATH value */ + FLOAT l[SBMAX_l]; /* ATH for sfbs in long blocks */ + FLOAT s[SBMAX_s]; /* ATH for sfbs in short blocks */ + FLOAT psfb21[PSFB21]; /* ATH for partitionned sfb21 in long blocks */ + FLOAT psfb12[PSFB12]; /* ATH for partitionned sfb12 in short blocks */ + FLOAT cb_l[CBANDS]; /* ATH for long block convolution bands */ + FLOAT cb_s[CBANDS]; /* ATH for short block convolution bands */ + FLOAT eql_w[BLKSIZE / 2]; /* equal loudness weights (based on ATH) */ + } ATH_t; + + /** + * PSY Model related stuff + */ + + typedef struct { + FLOAT masking_lower[CBANDS]; + FLOAT minval[CBANDS]; + FLOAT rnumlines[CBANDS]; + FLOAT mld_cb[CBANDS]; + FLOAT mld[Max(SBMAX_l,SBMAX_s)]; + FLOAT bo_weight[Max(SBMAX_l,SBMAX_s)]; /* band weight long scalefactor bands, at transition */ + FLOAT attack_threshold; /* short block tuning */ + int s3ind[CBANDS][2]; + int numlines[CBANDS]; + int bm[Max(SBMAX_l,SBMAX_s)]; + int bo[Max(SBMAX_l,SBMAX_s)]; + int npart; + int n_sb; /* SBMAX_l or SBMAX_s */ + FLOAT *s3; + } PsyConst_CB2SB_t; + + + /** + * global data constants + */ + typedef struct { + FLOAT window[BLKSIZE], window_s[BLKSIZE_s / 2]; + PsyConst_CB2SB_t l; + PsyConst_CB2SB_t s; + PsyConst_CB2SB_t l_to_s; + FLOAT attack_threshold[4]; + FLOAT decay; + int force_short_block_calc; + } PsyConst_t; + + + typedef struct { + + FLOAT nb_l1[4][CBANDS], nb_l2[4][CBANDS]; + FLOAT nb_s1[4][CBANDS], nb_s2[4][CBANDS]; + + III_psy_xmin thm[4]; + III_psy_xmin en[4]; + + /* loudness calculation (for adaptive threshold of hearing) */ + FLOAT loudness_sq_save[2]; /* account for granule delay of L3psycho_anal */ + + FLOAT tot_ener[4]; + + FLOAT last_en_subshort[4][9]; + int last_attacks[4]; + + int blocktype_old[2]; + } PsyStateVar_t; + + + typedef struct { + /* loudness calculation (for adaptive threshold of hearing) */ + FLOAT loudness_sq[2][2]; /* loudness^2 approx. per granule and channel */ + } PsyResult_t; + + + /* variables used by encoder.c */ + typedef struct { + /* variables for newmdct.c */ + FLOAT sb_sample[2][2][18][SBLIMIT]; + FLOAT amp_filter[32]; + + /* variables used by util.c */ + /* BPC = maximum number of filter convolution windows to precompute */ +#define BPC 320 + double itime[2]; /* float precision seems to be not enough */ + sample_t *inbuf_old[2]; + sample_t *blackfilt[2 * BPC + 1]; + + FLOAT pefirbuf[19]; + + /* used for padding */ + int frac_SpF; + int slot_lag; + + /* variables for bitstream.c */ + /* mpeg1: buffer=511 bytes smallest frame: 96-38(sideinfo)=58 + * max number of frames in reservoir: 8 + * mpeg2: buffer=255 bytes. smallest frame: 24-23bytes=1 + * with VBR, if you are encoding all silence, it is possible to + * have 8kbs/24khz frames with 1byte of data each, which means we need + * to buffer up to 255 headers! */ + /* also, max_header_buf has to be a power of two */ +#define MAX_HEADER_BUF 256 +#define MAX_HEADER_LEN 40 /* max size of header is 38 */ + struct { + int write_timing; + int ptr; + char buf[MAX_HEADER_LEN]; + } header[MAX_HEADER_BUF]; + + int h_ptr; + int w_ptr; + int ancillary_flag; + + /* variables for reservoir.c */ + int ResvSize; /* in bits */ + int ResvMax; /* in bits */ + + int in_buffer_nsamples; + sample_t *in_buffer_0; + sample_t *in_buffer_1; + +#ifndef MFSIZE +# define MFSIZE ( 3*1152 + ENCDELAY - MDCTDELAY ) +#endif + sample_t mfbuf[2][MFSIZE]; + + int mf_samples_to_encode; + int mf_size; + + } EncStateVar_t; + + + typedef struct { + /* simple statistics */ + int bitrate_channelmode_hist[16][4 + 1]; + int bitrate_blocktype_hist[16][4 + 1 + 1]; /*norm/start/short/stop/mixed(short)/sum */ + + int bitrate_index; + int frame_number; /* number of frames encoded */ + int padding; /* padding for the current frame? */ + int mode_ext; + int encoder_delay; + int encoder_padding; /* number of samples of padding appended to input */ + } EncResult_t; + + + /* variables used by quantize.c */ + typedef struct { + /* variables for nspsytune */ + FLOAT longfact[SBMAX_l]; + FLOAT shortfact[SBMAX_s]; + FLOAT masking_lower; + FLOAT mask_adjust; /* the dbQ stuff */ + FLOAT mask_adjust_short; /* the dbQ stuff */ + int OldValue[2]; + int CurrentStep[2]; + int pseudohalf[SFBMAX]; + int sfb21_extra; /* will be set in lame_init_params */ + int substep_shaping; /* 0 = no substep + 1 = use substep shaping at last step(VBR only) + (not implemented yet) + 2 = use substep inside loop + 3 = use substep inside loop and last step + */ + + + char bv_scf[576]; + } QntStateVar_t; + + + typedef struct { + replaygain_t *rgdata; + /* ReplayGain */ + } RpgStateVar_t; + + + typedef struct { + FLOAT noclipScale; /* user-specified scale factor required for preventing clipping */ + sample_t PeakSample; + int RadioGain; + int noclipGainChange; /* gain change required for preventing clipping */ + } RpgResult_t; + + + typedef struct { + int version; /* 0=MPEG-2/2.5 1=MPEG-1 */ + int samplerate_index; + int sideinfo_len; + + int noise_shaping; /* 0 = none + 1 = ISO AAC model + 2 = allow scalefac_select=1 + */ + + int subblock_gain; /* 0 = no, 1 = yes */ + int use_best_huffman; /* 0 = no. 1=outside loop 2=inside loop(slow) */ + int noise_shaping_amp; /* 0 = ISO model: amplify all distorted bands + 1 = amplify within 50% of max (on db scale) + 2 = amplify only most distorted band + 3 = method 1 and refine with method 2 + */ + + int noise_shaping_stop; /* 0 = stop at over=0, all scalefacs amplified or + a scalefac has reached max value + 1 = stop when all scalefacs amplified or + a scalefac has reached max value + 2 = stop when all scalefacs amplified + */ + + + int full_outer_loop; /* 0 = stop early after 0 distortion found. 1 = full search */ + + int lowpassfreq; + int highpassfreq; + int samplerate_in; /* input_samp_rate in Hz. default=44.1 kHz */ + int samplerate_out; /* output_samp_rate. */ + int channels_in; /* number of channels in the input data stream (PCM or decoded PCM) */ + int channels_out; /* number of channels in the output data stream (not used for decoding) */ + int mode_gr; /* granules per frame */ + int force_ms; /* force M/S mode. requires mode=1 */ + + int quant_comp; + int quant_comp_short; + + int use_temporal_masking_effect; + int use_safe_joint_stereo; + + int preset; + + vbr_mode vbr; + int vbr_avg_bitrate_kbps; + int vbr_min_bitrate_index; /* min bitrate index */ + int vbr_max_bitrate_index; /* max bitrate index */ + int avg_bitrate; + int enforce_min_bitrate; /* strictly enforce VBR_min_bitrate normaly, it will be violated for analog silence */ + + int findReplayGain; /* find the RG value? default=0 */ + int findPeakSample; + int decode_on_the_fly; /* decode on the fly? default=0 */ + int analysis; + int disable_reservoir; + int buffer_constraint; /* enforce ISO spec as much as possible */ + int free_format; + int write_lame_tag; /* add Xing VBR tag? */ + + int error_protection; /* use 2 bytes per frame for a CRC checksum. default=0 */ + int copyright; /* mark as copyright. default=0 */ + int original; /* mark as original. default=1 */ + int extension; /* the MP3 'private extension' bit. Meaningless */ + int emphasis; /* Input PCM is emphased PCM (for + instance from one of the rarely + emphased CDs), it is STRONGLY not + recommended to use this, because + psycho does not take it into account, + and last but not least many decoders + don't care about these bits */ + + + MPEG_mode mode; + short_block_t short_blocks; + + float interChRatio; + float msfix; /* Naoki's adjustment of Mid/Side maskings */ + float ATH_offset_db;/* add to ATH this many db */ + float ATH_offset_factor;/* change ATH by this factor, derived from ATH_offset_db */ + float ATHcurve; /* change ATH formula 4 shape */ + int ATHtype; + int ATHonly; /* only use ATH */ + int ATHshort; /* only use ATH for short blocks */ + int noATH; /* disable ATH */ + + float ATHfixpoint; + + float adjust_alto_db; + float adjust_bass_db; + float adjust_treble_db; + float adjust_sfb21_db; + + float compression_ratio; /* sizeof(wav file)/sizeof(mp3 file) */ + + /* lowpass and highpass filter control */ + FLOAT lowpass1, lowpass2; /* normalized frequency bounds of passband */ + FLOAT highpass1, highpass2; /* normalized frequency bounds of passband */ + + /* scale input by this amount before encoding at least not used for MP3 decoding */ + FLOAT pcm_transform[2][2]; + + FLOAT minval; + } SessionConfig_t; + + + struct lame_internal_flags { + + /******************************************************************** + * internal variables NOT set by calling program, and should not be * + * modified by the calling program * + ********************************************************************/ + + /* + * Some remarks to the Class_ID field: + * The Class ID is an Identifier for a pointer to this struct. + * It is very unlikely that a pointer to lame_global_flags has the same 32 bits + * in it's structure (large and other special properties, for instance prime). + * + * To test that the structure is right and initialized, use: + * if ( gfc -> Class_ID == LAME_ID ) ... + * Other remark: + * If you set a flag to 0 for uninit data and 1 for init data, the right test + * should be "if (flag == 1)" and NOT "if (flag)". Unintended modification + * of this element will be otherwise misinterpreted as an init. + */ +# define LAME_ID 0xFFF88E3B + unsigned long class_id; + + int lame_init_params_successful; + int lame_encode_frame_init; + int iteration_init_init; + int fill_buffer_resample_init; + + SessionConfig_t cfg; + + /* variables used by lame.c */ + Bit_stream_struc bs; + III_side_info_t l3_side; + + scalefac_struct scalefac_band; + + PsyStateVar_t sv_psy; /* DATA FROM PSYMODEL.C */ + PsyResult_t ov_psy; + EncStateVar_t sv_enc; /* DATA FROM ENCODER.C */ + EncResult_t ov_enc; + QntStateVar_t sv_qnt; /* DATA FROM QUANTIZE.C */ + + RpgStateVar_t sv_rpg; + RpgResult_t ov_rpg; + + /* optional ID3 tags, used in id3tag.c */ + struct id3tag_spec tag_spec; + uint16_t nMusicCRC; + + uint16_t _unused; + + /* CPU features */ + struct { + unsigned int MMX:1; /* Pentium MMX, Pentium II...IV, K6, K6-2, + K6-III, Athlon */ + unsigned int AMD_3DNow:1; /* K6-2, K6-III, Athlon */ + unsigned int SSE:1; /* Pentium III, Pentium 4 */ + unsigned int SSE2:1; /* Pentium 4, K8 */ + unsigned int _unused:28; + } CPU_features; + + + VBR_seek_info_t VBR_seek_table; /* used for Xing VBR header */ + + ATH_t *ATH; /* all ATH related stuff */ + + PsyConst_t *cd_psy; + + /* used by the frame analyzer */ + plotting_data *pinfo; + hip_t hip; + + /* functions to replace with CPU feature optimized versions in takehiro.c */ + int (*choose_table) (const int *ix, const int *const end, int *const s); + void (*fft_fht) (FLOAT *, int); + void (*init_xrpow_core) (gr_info * const cod_info, FLOAT xrpow[576], int upper, + FLOAT * sum); + + lame_report_function report_msg; + lame_report_function report_dbg; + lame_report_function report_err; + }; + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined + typedef struct lame_internal_flags lame_internal_flags; +#endif + + +/*********************************************************************** +* +* Global Function Prototype Declarations +* +***********************************************************************/ + void freegfc(lame_internal_flags * const gfc); + void free_id3tag(lame_internal_flags * const gfc); + extern int BitrateIndex(int, int, int); + extern int FindNearestBitrate(int, int, int); + extern int map2MP3Frequency(int freq); + extern int SmpFrqIndex(int, int *const); + extern int nearestBitrateFullIndex(uint16_t brate); + extern FLOAT ATHformula(SessionConfig_t const *cfg, FLOAT freq); + extern FLOAT freq2bark(FLOAT freq); + void disable_FPE(void); + +/* log/log10 approximations */ + extern void init_log_table(void); + extern ieee754_float32_t fast_log2(ieee754_float32_t x); + + int isResamplingNecessary(SessionConfig_t const* cfg); + + void fill_buffer(lame_internal_flags * gfc, + sample_t *const mfbuf[2], + sample_t const *const in_buffer[2], int nsamples, int *n_in, int *n_out); + +/* same as lame_decode1 (look in lame.h), but returns + unclipped raw floating-point samples. It is declared + here, not in lame.h, because it returns LAME's + internal type sample_t. No more than 1152 samples + per channel are allowed. */ + int hip_decode1_unclipped(hip_t hip, unsigned char *mp3buf, + size_t len, sample_t pcm_l[], sample_t pcm_r[]); + + + extern int has_MMX(void); + extern int has_3DNow(void); + extern int has_SSE(void); + extern int has_SSE2(void); + + + +/*********************************************************************** +* +* Macros about Message Printing and Exit +* +***********************************************************************/ + + extern void lame_report_def(const char* format, va_list args); + extern void lame_report_fnc(lame_report_function print_f, const char *, ...); + extern void lame_errorf(const lame_internal_flags * gfc, const char *, ...); + extern void lame_debugf(const lame_internal_flags * gfc, const char *, ...); + extern void lame_msgf(const lame_internal_flags * gfc, const char *, ...); +#define DEBUGF lame_debugf +#define ERRORF lame_errorf +#define MSGF lame_msgf + + int is_lame_internal_flags_valid(const lame_internal_flags * gfp); + + extern void hip_set_pinfo(hip_t hip, plotting_data* pinfo); + +#ifdef __cplusplus +} +#endif +#endif /* LAME_UTIL_H */ diff --git a/pkg/lame/clame/vbrquantize.c b/pkg/lame/clame/vbrquantize.c new file mode 100644 index 0000000..0f703b7 --- /dev/null +++ b/pkg/lame/clame/vbrquantize.c @@ -0,0 +1,1580 @@ +/* + * MP3 quantization + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2000-2012 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: vbrquantize.c,v 1.142 2012/02/07 13:36:35 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "vbrquantize.h" +#include "quantize_pvt.h" + + + + +struct algo_s; +typedef struct algo_s algo_t; + +typedef void (*alloc_sf_f) (const algo_t *, const int *, const int *, int); +typedef uint8_t (*find_sf_f) (const FLOAT *, const FLOAT *, FLOAT, unsigned int, uint8_t); + +struct algo_s { + alloc_sf_f alloc; + find_sf_f find; + const FLOAT *xr34orig; + lame_internal_flags *gfc; + gr_info *cod_info; + int mingain_l; + int mingain_s[3]; +}; + + + +/* Remarks on optimizing compilers: + * + * the MSVC compiler may get into aliasing problems when accessing + * memory through the fi_union. declaring it volatile does the trick here + * + * the calc_sfb_noise_* functions are not inlined because the intel compiler + * optimized executeables won't work as expected anymore + */ + +#ifdef _MSC_VER +# if _MSC_VER < 1400 +# define VOLATILE volatile +# else +# define VOLATILE +# endif +#else +# define VOLATILE +#endif + +typedef VOLATILE union { + float f; + int i; +} fi_union; + + + +#ifdef TAKEHIRO_IEEE754_HACK +#define DOUBLEX double +#else +#define DOUBLEX FLOAT +#endif + +#define MAGIC_FLOAT_def (65536*(128)) +#define MAGIC_INT_def 0x4b000000 + +#ifdef TAKEHIRO_IEEE754_HACK +#else +/********************************************************************* + * XRPOW_FTOI is a macro to convert floats to ints. + * if XRPOW_FTOI(x) = nearest_int(x), then QUANTFAC(x)=adj43asm[x] + * ROUNDFAC= -0.0946 + * + * if XRPOW_FTOI(x) = floor(x), then QUANTFAC(x)=asj43[x] + * ROUNDFAC=0.4054 + *********************************************************************/ +# define QUANTFAC(rx) adj43[rx] +# define ROUNDFAC_def 0.4054f +# define XRPOW_FTOI(src,dest) ((dest) = (int)(src)) +#endif + +static int const MAGIC_INT = MAGIC_INT_def; +#ifndef TAKEHIRO_IEEE754_HACK +static DOUBLEX const ROUNDFAC = ROUNDFAC_def; +#endif +static DOUBLEX const MAGIC_FLOAT = MAGIC_FLOAT_def; + + +inline static float +vec_max_c(const float * xr34, unsigned int bw) +{ + float xfsf = 0; + unsigned int i = bw >> 2u; + unsigned int const remaining = (bw & 0x03u); + + while (i-- > 0) { + if (xfsf < xr34[0]) { + xfsf = xr34[0]; + } + if (xfsf < xr34[1]) { + xfsf = xr34[1]; + } + if (xfsf < xr34[2]) { + xfsf = xr34[2]; + } + if (xfsf < xr34[3]) { + xfsf = xr34[3]; + } + xr34 += 4; + } + switch( remaining ) { + case 3: if (xfsf < xr34[2]) xfsf = xr34[2]; + case 2: if (xfsf < xr34[1]) xfsf = xr34[1]; + case 1: if (xfsf < xr34[0]) xfsf = xr34[0]; + default: break; + } + return xfsf; +} + + +inline static uint8_t +find_lowest_scalefac(const FLOAT xr34) +{ + uint8_t sf_ok = 255; + uint8_t sf = 128, delsf = 64; + uint8_t i; + FLOAT const ixmax_val = IXMAX_VAL; + for (i = 0; i < 8; ++i) { + FLOAT const xfsf = ipow20[sf] * xr34; + if (xfsf <= ixmax_val) { + sf_ok = sf; + sf -= delsf; + } + else { + sf += delsf; + } + delsf >>= 1; + } + return sf_ok; +} + + +inline static void +k_34_4(DOUBLEX x[4], int l3[4]) +{ +#ifdef TAKEHIRO_IEEE754_HACK + fi_union fi[4]; + + assert(x[0] <= IXMAX_VAL && x[1] <= IXMAX_VAL && x[2] <= IXMAX_VAL && x[3] <= IXMAX_VAL); + x[0] += MAGIC_FLOAT; + fi[0].f = x[0]; + x[1] += MAGIC_FLOAT; + fi[1].f = x[1]; + x[2] += MAGIC_FLOAT; + fi[2].f = x[2]; + x[3] += MAGIC_FLOAT; + fi[3].f = x[3]; + fi[0].f = x[0] + adj43asm[fi[0].i - MAGIC_INT]; + fi[1].f = x[1] + adj43asm[fi[1].i - MAGIC_INT]; + fi[2].f = x[2] + adj43asm[fi[2].i - MAGIC_INT]; + fi[3].f = x[3] + adj43asm[fi[3].i - MAGIC_INT]; + l3[0] = fi[0].i - MAGIC_INT; + l3[1] = fi[1].i - MAGIC_INT; + l3[2] = fi[2].i - MAGIC_INT; + l3[3] = fi[3].i - MAGIC_INT; +#else + assert(x[0] <= IXMAX_VAL && x[1] <= IXMAX_VAL && x[2] <= IXMAX_VAL && x[3] <= IXMAX_VAL); + XRPOW_FTOI(x[0], l3[0]); + XRPOW_FTOI(x[1], l3[1]); + XRPOW_FTOI(x[2], l3[2]); + XRPOW_FTOI(x[3], l3[3]); + x[0] += QUANTFAC(l3[0]); + x[1] += QUANTFAC(l3[1]); + x[2] += QUANTFAC(l3[2]); + x[3] += QUANTFAC(l3[3]); + XRPOW_FTOI(x[0], l3[0]); + XRPOW_FTOI(x[1], l3[1]); + XRPOW_FTOI(x[2], l3[2]); + XRPOW_FTOI(x[3], l3[3]); +#endif +} + + + + + +/* do call the calc_sfb_noise_* functions only with sf values + * for which holds: sfpow34*xr34 <= IXMAX_VAL + */ + +static FLOAT +calc_sfb_noise_x34(const FLOAT * xr, const FLOAT * xr34, unsigned int bw, uint8_t sf) +{ + DOUBLEX x[4]; + int l3[4]; + const FLOAT sfpow = pow20[sf + Q_MAX2]; /*pow(2.0,sf/4.0); */ + const FLOAT sfpow34 = ipow20[sf]; /*pow(sfpow,-3.0/4.0); */ + + FLOAT xfsf = 0; + unsigned int i = bw >> 2u; + unsigned int const remaining = (bw & 0x03u); + + while (i-- > 0) { + x[0] = sfpow34 * xr34[0]; + x[1] = sfpow34 * xr34[1]; + x[2] = sfpow34 * xr34[2]; + x[3] = sfpow34 * xr34[3]; + + k_34_4(x, l3); + + x[0] = fabsf(xr[0]) - sfpow * pow43[l3[0]]; + x[1] = fabsf(xr[1]) - sfpow * pow43[l3[1]]; + x[2] = fabsf(xr[2]) - sfpow * pow43[l3[2]]; + x[3] = fabsf(xr[3]) - sfpow * pow43[l3[3]]; + xfsf += (x[0] * x[0] + x[1] * x[1]) + (x[2] * x[2] + x[3] * x[3]); + + xr += 4; + xr34 += 4; + } + if (remaining) { + x[0] = x[1] = x[2] = x[3] = 0; + switch( remaining ) { + case 3: x[2] = sfpow34 * xr34[2]; + case 2: x[1] = sfpow34 * xr34[1]; + case 1: x[0] = sfpow34 * xr34[0]; + } + + k_34_4(x, l3); + x[0] = x[1] = x[2] = x[3] = 0; + + switch( remaining ) { + case 3: x[2] = fabsf(xr[2]) - sfpow * pow43[l3[2]]; + case 2: x[1] = fabsf(xr[1]) - sfpow * pow43[l3[1]]; + case 1: x[0] = fabsf(xr[0]) - sfpow * pow43[l3[0]]; + } + xfsf += (x[0] * x[0] + x[1] * x[1]) + (x[2] * x[2] + x[3] * x[3]); + } + return xfsf; +} + + + +struct calc_noise_cache { + int valid; + FLOAT value; +}; + +typedef struct calc_noise_cache calc_noise_cache_t; + + +static uint8_t +tri_calc_sfb_noise_x34(const FLOAT * xr, const FLOAT * xr34, FLOAT l3_xmin, unsigned int bw, + uint8_t sf, calc_noise_cache_t * did_it) +{ + if (did_it[sf].valid == 0) { + did_it[sf].valid = 1; + did_it[sf].value = calc_sfb_noise_x34(xr, xr34, bw, sf); + } + if (l3_xmin < did_it[sf].value) { + return 1; + } + if (sf < 255) { + uint8_t const sf_x = sf + 1; + if (did_it[sf_x].valid == 0) { + did_it[sf_x].valid = 1; + did_it[sf_x].value = calc_sfb_noise_x34(xr, xr34, bw, sf_x); + } + if (l3_xmin < did_it[sf_x].value) { + return 1; + } + } + if (sf > 0) { + uint8_t const sf_x = sf - 1; + if (did_it[sf_x].valid == 0) { + did_it[sf_x].valid = 1; + did_it[sf_x].value = calc_sfb_noise_x34(xr, xr34, bw, sf_x); + } + if (l3_xmin < did_it[sf_x].value) { + return 1; + } + } + return 0; +} + + +/** + * Robert Hegemann 2001-05-01 + * calculates quantization step size determined by allowed masking + */ +static int +calc_scalefac(FLOAT l3_xmin, int bw) +{ + FLOAT const c = 5.799142446; /* 10 * 10^(2/3) * log10(4/3) */ + return 210 + (int) (c * log10f(l3_xmin / bw) - .5f); +} + +static uint8_t +guess_scalefac_x34(const FLOAT * xr, const FLOAT * xr34, FLOAT l3_xmin, unsigned int bw, uint8_t sf_min) +{ + int const guess = calc_scalefac(l3_xmin, bw); + if (guess < sf_min) return sf_min; + if (guess >= 255) return 255; + (void) xr; + (void) xr34; + return guess; +} + + +/* the find_scalefac* routines calculate + * a quantization step size which would + * introduce as much noise as is allowed. + * The larger the step size the more + * quantization noise we'll get. The + * scalefactors are there to lower the + * global step size, allowing limited + * differences in quantization step sizes + * per band (shaping the noise). + */ + +static uint8_t +find_scalefac_x34(const FLOAT * xr, const FLOAT * xr34, FLOAT l3_xmin, unsigned int bw, + uint8_t sf_min) +{ + calc_noise_cache_t did_it[256]; + uint8_t sf = 128, sf_ok = 255, delsf = 128, seen_good_one = 0, i; + memset(did_it, 0, sizeof(did_it)); + for (i = 0; i < 8; ++i) { + delsf >>= 1; + if (sf <= sf_min) { + sf += delsf; + } + else { + uint8_t const bad = tri_calc_sfb_noise_x34(xr, xr34, l3_xmin, bw, sf, did_it); + if (bad) { /* distortion. try a smaller scalefactor */ + sf -= delsf; + } + else { + sf_ok = sf; + sf += delsf; + seen_good_one = 1; + } + } + } + /* returning a scalefac without distortion, if possible + */ + if (seen_good_one > 0) { + sf = sf_ok; + } + if (sf <= sf_min) { + sf = sf_min; + } + return sf; +} + + + +/*********************************************************************** + * + * calc_short_block_vbr_sf() + * calc_long_block_vbr_sf() + * + * Mark Taylor 2000-??-?? + * Robert Hegemann 2000-10-25 made functions of it + * + ***********************************************************************/ + +/* a variation for vbr-mtrh */ +static int +block_sf(algo_t * that, const FLOAT l3_xmin[SFBMAX], int vbrsf[SFBMAX], int vbrsfmin[SFBMAX]) +{ + FLOAT max_xr34; + const FLOAT *const xr = &that->cod_info->xr[0]; + const FLOAT *const xr34_orig = &that->xr34orig[0]; + const int *const width = &that->cod_info->width[0]; + const char *const energy_above_cutoff = &that->cod_info->energy_above_cutoff[0]; + unsigned int const max_nonzero_coeff = (unsigned int) that->cod_info->max_nonzero_coeff; + uint8_t maxsf = 0; + int sfb = 0, m_o = -1; + unsigned int j = 0, i = 0; + int const psymax = that->cod_info->psymax; + + assert(that->cod_info->max_nonzero_coeff >= 0); + + that->mingain_l = 0; + that->mingain_s[0] = 0; + that->mingain_s[1] = 0; + that->mingain_s[2] = 0; + while (j <= max_nonzero_coeff) { + unsigned int const w = (unsigned int) width[sfb]; + unsigned int const m = (unsigned int) (max_nonzero_coeff - j + 1); + unsigned int l = w; + uint8_t m1, m2; + if (l > m) { + l = m; + } + max_xr34 = vec_max_c(&xr34_orig[j], l); + + m1 = find_lowest_scalefac(max_xr34); + vbrsfmin[sfb] = m1; + if (that->mingain_l < m1) { + that->mingain_l = m1; + } + if (that->mingain_s[i] < m1) { + that->mingain_s[i] = m1; + } + if (++i > 2) { + i = 0; + } + if (sfb < psymax && w > 2) { /* mpeg2.5 at 8 kHz doesn't use all scalefactors, unused have width 2 */ + if (energy_above_cutoff[sfb]) { + m2 = that->find(&xr[j], &xr34_orig[j], l3_xmin[sfb], l, m1); +#if 0 + if (0) { + /** Robert Hegemann 2007-09-29: + * It seems here is some more potential for speed improvements. + * Current find method does 11-18 quantization calculations. + * Using a "good guess" may help to reduce this amount. + */ + uint8_t guess = calc_scalefac(l3_xmin[sfb], l); + DEBUGF(that->gfc, "sfb=%3d guess=%3d found=%3d diff=%3d\n", sfb, guess, m2, + m2 - guess); + } +#endif + if (maxsf < m2) { + maxsf = m2; + } + if (m_o < m2 && m2 < 255) { + m_o = m2; + } + } + else { + m2 = 255; + maxsf = 255; + } + } + else { + if (maxsf < m1) { + maxsf = m1; + } + m2 = maxsf; + } + vbrsf[sfb] = m2; + ++sfb; + j += w; + } + for (; sfb < SFBMAX; ++sfb) { + vbrsf[sfb] = maxsf; + vbrsfmin[sfb] = 0; + } + if (m_o > -1) { + maxsf = m_o; + for (sfb = 0; sfb < SFBMAX; ++sfb) { + if (vbrsf[sfb] == 255) { + vbrsf[sfb] = m_o; + } + } + } + return maxsf; +} + + + +/*********************************************************************** + * + * quantize xr34 based on scalefactors + * + * block_xr34 + * + * Mark Taylor 2000-??-?? + * Robert Hegemann 2000-10-20 made functions of them + * + ***********************************************************************/ + +static void +quantize_x34(const algo_t * that) +{ + DOUBLEX x[4]; + const FLOAT *xr34_orig = that->xr34orig; + gr_info *const cod_info = that->cod_info; + int const ifqstep = (cod_info->scalefac_scale == 0) ? 2 : 4; + int *l3 = cod_info->l3_enc; + unsigned int j = 0, sfb = 0; + unsigned int const max_nonzero_coeff = (unsigned int) cod_info->max_nonzero_coeff; + + assert(cod_info->max_nonzero_coeff >= 0); + assert(cod_info->max_nonzero_coeff < 576); + + while (j <= max_nonzero_coeff) { + int const s = + (cod_info->scalefac[sfb] + (cod_info->preflag ? pretab[sfb] : 0)) * ifqstep + + cod_info->subblock_gain[cod_info->window[sfb]] * 8; + uint8_t const sfac = (uint8_t) (cod_info->global_gain - s); + FLOAT const sfpow34 = ipow20[sfac]; + unsigned int const w = (unsigned int) cod_info->width[sfb]; + unsigned int const m = (unsigned int) (max_nonzero_coeff - j + 1); + unsigned int i, remaining; + + assert((cod_info->global_gain - s) >= 0); + assert(cod_info->width[sfb] >= 0); + j += w; + ++sfb; + + i = (w <= m) ? w : m; + remaining = (i & 0x03u); + i >>= 2u; + + while (i-- > 0) { + x[0] = sfpow34 * xr34_orig[0]; + x[1] = sfpow34 * xr34_orig[1]; + x[2] = sfpow34 * xr34_orig[2]; + x[3] = sfpow34 * xr34_orig[3]; + + k_34_4(x, l3); + + l3 += 4; + xr34_orig += 4; + } + if (remaining) { + int tmp_l3[4]; + x[0] = x[1] = x[2] = x[3] = 0; + switch( remaining ) { + case 3: x[2] = sfpow34 * xr34_orig[2]; + case 2: x[1] = sfpow34 * xr34_orig[1]; + case 1: x[0] = sfpow34 * xr34_orig[0]; + } + + k_34_4(x, tmp_l3); + + switch( remaining ) { + case 3: l3[2] = tmp_l3[2]; + case 2: l3[1] = tmp_l3[1]; + case 1: l3[0] = tmp_l3[0]; + } + + l3 += remaining; + xr34_orig += remaining; + } + } +} + + + +static const uint8_t max_range_short[SBMAX_s * 3] = { + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 0, 0 +}; + +static const uint8_t max_range_long[SBMAX_l] = { + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0 +}; + +static const uint8_t max_range_long_lsf_pretab[SBMAX_l] = { + 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + + +/* + sfb=0..5 scalefac < 16 + sfb>5 scalefac < 8 + + ifqstep = ( cod_info->scalefac_scale == 0 ) ? 2 : 4; + ol_sf = (cod_info->global_gain-210.0); + ol_sf -= 8*cod_info->subblock_gain[i]; + ol_sf -= ifqstep*scalefac[gr][ch].s[sfb][i]; +*/ + +static void +set_subblock_gain(gr_info * cod_info, const int mingain_s[3], int sf[]) +{ + const int maxrange1 = 15, maxrange2 = 7; + const int ifqstepShift = (cod_info->scalefac_scale == 0) ? 1 : 2; + int *const sbg = cod_info->subblock_gain; + unsigned int const psymax = (unsigned int) cod_info->psymax; + unsigned int psydiv = 18; + int sbg0, sbg1, sbg2; + unsigned int sfb, i; + int min_sbg = 7; + + if (psydiv > psymax) { + psydiv = psymax; + } + for (i = 0; i < 3; ++i) { + int maxsf1 = 0, maxsf2 = 0, minsf = 1000; + /* see if we should use subblock gain */ + for (sfb = i; sfb < psydiv; sfb += 3) { /* part 1 */ + int const v = -sf[sfb]; + if (maxsf1 < v) { + maxsf1 = v; + } + if (minsf > v) { + minsf = v; + } + } + for (; sfb < SFBMAX; sfb += 3) { /* part 2 */ + int const v = -sf[sfb]; + if (maxsf2 < v) { + maxsf2 = v; + } + if (minsf > v) { + minsf = v; + } + } + + /* boost subblock gain as little as possible so we can + * reach maxsf1 with scalefactors + * 8*sbg >= maxsf1 + */ + { + int const m1 = maxsf1 - (maxrange1 << ifqstepShift); + int const m2 = maxsf2 - (maxrange2 << ifqstepShift); + + maxsf1 = Max(m1, m2); + } + if (minsf > 0) { + sbg[i] = minsf >> 3; + } + else { + sbg[i] = 0; + } + if (maxsf1 > 0) { + int const m1 = sbg[i]; + int const m2 = (maxsf1 + 7) >> 3; + sbg[i] = Max(m1, m2); + } + if (sbg[i] > 0 && mingain_s[i] > (cod_info->global_gain - sbg[i] * 8)) { + sbg[i] = (cod_info->global_gain - mingain_s[i]) >> 3; + } + if (sbg[i] > 7) { + sbg[i] = 7; + } + if (min_sbg > sbg[i]) { + min_sbg = sbg[i]; + } + } + sbg0 = sbg[0] * 8; + sbg1 = sbg[1] * 8; + sbg2 = sbg[2] * 8; + for (sfb = 0; sfb < SFBMAX; sfb += 3) { + sf[sfb + 0] += sbg0; + sf[sfb + 1] += sbg1; + sf[sfb + 2] += sbg2; + } + if (min_sbg > 0) { + for (i = 0; i < 3; ++i) { + sbg[i] -= min_sbg; + } + cod_info->global_gain -= min_sbg * 8; + } +} + + + +/* + ifqstep = ( cod_info->scalefac_scale == 0 ) ? 2 : 4; + ol_sf = (cod_info->global_gain-210.0); + ol_sf -= ifqstep*scalefac[gr][ch].l[sfb]; + if (cod_info->preflag && sfb>=11) + ol_sf -= ifqstep*pretab[sfb]; +*/ +static void +set_scalefacs(gr_info * cod_info, const int *vbrsfmin, int sf[], const uint8_t * max_range) +{ + const int ifqstep = (cod_info->scalefac_scale == 0) ? 2 : 4; + const int ifqstepShift = (cod_info->scalefac_scale == 0) ? 1 : 2; + int *const scalefac = cod_info->scalefac; + int const sfbmax = cod_info->sfbmax; + int sfb; + int const *const sbg = cod_info->subblock_gain; + int const *const window = cod_info->window; + int const preflag = cod_info->preflag; + + if (preflag) { + for (sfb = 11; sfb < sfbmax; ++sfb) { + sf[sfb] += pretab[sfb] * ifqstep; + } + } + for (sfb = 0; sfb < sfbmax; ++sfb) { + int const gain = cod_info->global_gain - (sbg[window[sfb]] * 8) + - ((preflag ? pretab[sfb] : 0) * ifqstep); + + if (sf[sfb] < 0) { + int const m = gain - vbrsfmin[sfb]; + /* ifqstep*scalefac >= -sf[sfb], so round UP */ + scalefac[sfb] = (ifqstep - 1 - sf[sfb]) >> ifqstepShift; + + if (scalefac[sfb] > max_range[sfb]) { + scalefac[sfb] = max_range[sfb]; + } + if (scalefac[sfb] > 0 && (scalefac[sfb] << ifqstepShift) > m) { + scalefac[sfb] = m >> ifqstepShift; + } + } + else { + scalefac[sfb] = 0; + } + } + for (; sfb < SFBMAX; ++sfb) { + scalefac[sfb] = 0; /* sfb21 */ + } +} + + +#ifndef NDEBUG +static int +checkScalefactor(const gr_info * cod_info, const int vbrsfmin[SFBMAX]) +{ + int const ifqstep = cod_info->scalefac_scale == 0 ? 2 : 4; + int sfb; + for (sfb = 0; sfb < cod_info->psymax; ++sfb) { + const int s = + ((cod_info->scalefac[sfb] + + (cod_info->preflag ? pretab[sfb] : 0)) * ifqstep) + + cod_info->subblock_gain[cod_info->window[sfb]] * 8; + + if ((cod_info->global_gain - s) < vbrsfmin[sfb]) { + /* + fprintf( stdout, "sf %d\n", sfb ); + fprintf( stdout, "min %d\n", vbrsfmin[sfb] ); + fprintf( stdout, "ggain %d\n", cod_info->global_gain ); + fprintf( stdout, "scalefac %d\n", cod_info->scalefac[sfb] ); + fprintf( stdout, "pretab %d\n", (cod_info->preflag ? pretab[sfb] : 0) ); + fprintf( stdout, "scale %d\n", (cod_info->scalefac_scale + 1) ); + fprintf( stdout, "subgain %d\n", cod_info->subblock_gain[cod_info->window[sfb]] * 8 ); + fflush( stdout ); + exit(-1); + */ + return 0; + } + } + return 1; +} +#endif + + +/****************************************************************** + * + * short block scalefacs + * + ******************************************************************/ + +static void +short_block_constrain(const algo_t * that, const int vbrsf[SFBMAX], + const int vbrsfmin[SFBMAX], int vbrmax) +{ + gr_info *const cod_info = that->cod_info; + lame_internal_flags const *const gfc = that->gfc; + SessionConfig_t const *const cfg = &gfc->cfg; + int const maxminsfb = that->mingain_l; + int mover, maxover0 = 0, maxover1 = 0, delta = 0; + int v, v0, v1; + int sfb; + int const psymax = cod_info->psymax; + + for (sfb = 0; sfb < psymax; ++sfb) { + assert(vbrsf[sfb] >= vbrsfmin[sfb]); + v = vbrmax - vbrsf[sfb]; + if (delta < v) { + delta = v; + } + v0 = v - (4 * 14 + 2 * max_range_short[sfb]); + v1 = v - (4 * 14 + 4 * max_range_short[sfb]); + if (maxover0 < v0) { + maxover0 = v0; + } + if (maxover1 < v1) { + maxover1 = v1; + } + } + if (cfg->noise_shaping == 2) { + /* allow scalefac_scale=1 */ + mover = Min(maxover0, maxover1); + } + else { + mover = maxover0; + } + if (delta > mover) { + delta = mover; + } + vbrmax -= delta; + maxover0 -= mover; + maxover1 -= mover; + + if (maxover0 == 0) { + cod_info->scalefac_scale = 0; + } + else if (maxover1 == 0) { + cod_info->scalefac_scale = 1; + } + if (vbrmax < maxminsfb) { + vbrmax = maxminsfb; + } + cod_info->global_gain = vbrmax; + + if (cod_info->global_gain < 0) { + cod_info->global_gain = 0; + } + else if (cod_info->global_gain > 255) { + cod_info->global_gain = 255; + } + { + int sf_temp[SFBMAX]; + for (sfb = 0; sfb < SFBMAX; ++sfb) { + sf_temp[sfb] = vbrsf[sfb] - vbrmax; + } + set_subblock_gain(cod_info, &that->mingain_s[0], sf_temp); + set_scalefacs(cod_info, vbrsfmin, sf_temp, max_range_short); + } + assert(checkScalefactor(cod_info, vbrsfmin)); +} + + + +/****************************************************************** + * + * long block scalefacs + * + ******************************************************************/ + +static void +long_block_constrain(const algo_t * that, const int vbrsf[SFBMAX], const int vbrsfmin[SFBMAX], + int vbrmax) +{ + gr_info *const cod_info = that->cod_info; + lame_internal_flags const *const gfc = that->gfc; + SessionConfig_t const *const cfg = &gfc->cfg; + uint8_t const *max_rangep; + int const maxminsfb = that->mingain_l; + int sfb; + int maxover0, maxover1, maxover0p, maxover1p, mover, delta = 0; + int v, v0, v1, v0p, v1p, vm0p = 1, vm1p = 1; + int const psymax = cod_info->psymax; + + max_rangep = cfg->mode_gr == 2 ? max_range_long : max_range_long_lsf_pretab; + + maxover0 = 0; + maxover1 = 0; + maxover0p = 0; /* pretab */ + maxover1p = 0; /* pretab */ + + for (sfb = 0; sfb < psymax; ++sfb) { + assert(vbrsf[sfb] >= vbrsfmin[sfb]); + v = vbrmax - vbrsf[sfb]; + if (delta < v) { + delta = v; + } + v0 = v - 2 * max_range_long[sfb]; + v1 = v - 4 * max_range_long[sfb]; + v0p = v - 2 * (max_rangep[sfb] + pretab[sfb]); + v1p = v - 4 * (max_rangep[sfb] + pretab[sfb]); + if (maxover0 < v0) { + maxover0 = v0; + } + if (maxover1 < v1) { + maxover1 = v1; + } + if (maxover0p < v0p) { + maxover0p = v0p; + } + if (maxover1p < v1p) { + maxover1p = v1p; + } + } + if (vm0p == 1) { + int gain = vbrmax - maxover0p; + if (gain < maxminsfb) { + gain = maxminsfb; + } + for (sfb = 0; sfb < psymax; ++sfb) { + int const a = (gain - vbrsfmin[sfb]) - 2 * pretab[sfb]; + if (a <= 0) { + vm0p = 0; + vm1p = 0; + break; + } + } + } + if (vm1p == 1) { + int gain = vbrmax - maxover1p; + if (gain < maxminsfb) { + gain = maxminsfb; + } + for (sfb = 0; sfb < psymax; ++sfb) { + int const b = (gain - vbrsfmin[sfb]) - 4 * pretab[sfb]; + if (b <= 0) { + vm1p = 0; + break; + } + } + } + if (vm0p == 0) { + maxover0p = maxover0; + } + if (vm1p == 0) { + maxover1p = maxover1; + } + if (cfg->noise_shaping != 2) { + maxover1 = maxover0; + maxover1p = maxover0p; + } + mover = Min(maxover0, maxover0p); + mover = Min(mover, maxover1); + mover = Min(mover, maxover1p); + + if (delta > mover) { + delta = mover; + } + vbrmax -= delta; + if (vbrmax < maxminsfb) { + vbrmax = maxminsfb; + } + maxover0 -= mover; + maxover0p -= mover; + maxover1 -= mover; + maxover1p -= mover; + + if (maxover0 == 0) { + cod_info->scalefac_scale = 0; + cod_info->preflag = 0; + max_rangep = max_range_long; + } + else if (maxover0p == 0) { + cod_info->scalefac_scale = 0; + cod_info->preflag = 1; + } + else if (maxover1 == 0) { + cod_info->scalefac_scale = 1; + cod_info->preflag = 0; + max_rangep = max_range_long; + } + else if (maxover1p == 0) { + cod_info->scalefac_scale = 1; + cod_info->preflag = 1; + } + else { + assert(0); /* this should not happen */ + } + cod_info->global_gain = vbrmax; + if (cod_info->global_gain < 0) { + cod_info->global_gain = 0; + } + else if (cod_info->global_gain > 255) { + cod_info->global_gain = 255; + } + { + int sf_temp[SFBMAX]; + for (sfb = 0; sfb < SFBMAX; ++sfb) { + sf_temp[sfb] = vbrsf[sfb] - vbrmax; + } + set_scalefacs(cod_info, vbrsfmin, sf_temp, max_rangep); + } + assert(checkScalefactor(cod_info, vbrsfmin)); +} + + + +static void +bitcount(const algo_t * that) +{ + int rc = scale_bitcount(that->gfc, that->cod_info); + + if (rc == 0) { + return; + } + /* this should not happen due to the way the scalefactors are selected */ + ERRORF(that->gfc, "INTERNAL ERROR IN VBR NEW CODE (986), please send bug report\n"); + exit(-1); +} + + + +static int +quantizeAndCountBits(const algo_t * that) +{ + quantize_x34(that); + that->cod_info->part2_3_length = noquant_count_bits(that->gfc, that->cod_info, 0); + return that->cod_info->part2_3_length; +} + + + + + +static int +tryGlobalStepsize(const algo_t * that, const int sfwork[SFBMAX], + const int vbrsfmin[SFBMAX], int delta) +{ + FLOAT const xrpow_max = that->cod_info->xrpow_max; + int sftemp[SFBMAX], i, nbits; + int gain, vbrmax = 0; + for (i = 0; i < SFBMAX; ++i) { + gain = sfwork[i] + delta; + if (gain < vbrsfmin[i]) { + gain = vbrsfmin[i]; + } + if (gain > 255) { + gain = 255; + } + if (vbrmax < gain) { + vbrmax = gain; + } + sftemp[i] = gain; + } + that->alloc(that, sftemp, vbrsfmin, vbrmax); + bitcount(that); + nbits = quantizeAndCountBits(that); + that->cod_info->xrpow_max = xrpow_max; + return nbits; +} + + + +static void +searchGlobalStepsizeMax(const algo_t * that, const int sfwork[SFBMAX], + const int vbrsfmin[SFBMAX], int target) +{ + gr_info const *const cod_info = that->cod_info; + const int gain = cod_info->global_gain; + int curr = gain; + int gain_ok = 1024; + int nbits = LARGE_BITS; + int l = gain, r = 512; + + assert(gain >= 0); + while (l <= r) { + curr = (l + r) >> 1; + nbits = tryGlobalStepsize(that, sfwork, vbrsfmin, curr - gain); + if (nbits == 0 || (nbits + cod_info->part2_length) < target) { + r = curr - 1; + gain_ok = curr; + } + else { + l = curr + 1; + if (gain_ok == 1024) { + gain_ok = curr; + } + } + } + if (gain_ok != curr) { + curr = gain_ok; + nbits = tryGlobalStepsize(that, sfwork, vbrsfmin, curr - gain); + } +} + + + +static int +sfDepth(const int sfwork[SFBMAX]) +{ + int m = 0; + unsigned int i, j; + for (j = SFBMAX, i = 0; j > 0; --j, ++i) { + int const di = 255 - sfwork[i]; + if (m < di) { + m = di; + } + assert(sfwork[i] >= 0); + assert(sfwork[i] <= 255); + } + assert(m >= 0); + assert(m <= 255); + return m; +} + + +static void +cutDistribution(const int sfwork[SFBMAX], int sf_out[SFBMAX], int cut) +{ + unsigned int i, j; + for (j = SFBMAX, i = 0; j > 0; --j, ++i) { + int const x = sfwork[i]; + sf_out[i] = x < cut ? x : cut; + } +} + + +static int +flattenDistribution(const int sfwork[SFBMAX], int sf_out[SFBMAX], int dm, int k, int p) +{ + unsigned int i, j; + int x, sfmax = 0; + if (dm > 0) { + for (j = SFBMAX, i = 0; j > 0; --j, ++i) { + int const di = p - sfwork[i]; + x = sfwork[i] + (k * di) / dm; + if (x < 0) { + x = 0; + } + else { + if (x > 255) { + x = 255; + } + } + sf_out[i] = x; + if (sfmax < x) { + sfmax = x; + } + } + } + else { + for (j = SFBMAX, i = 0; j > 0u; --j, ++i) { + x = sfwork[i]; + sf_out[i] = x; + if (sfmax < x) { + sfmax = x; + } + } + } + return sfmax; +} + + +static int +tryThatOne(algo_t const* that, const int sftemp[SFBMAX], const int vbrsfmin[SFBMAX], int vbrmax) +{ + FLOAT const xrpow_max = that->cod_info->xrpow_max; + int nbits = LARGE_BITS; + that->alloc(that, sftemp, vbrsfmin, vbrmax); + bitcount(that); + nbits = quantizeAndCountBits(that); + nbits += that->cod_info->part2_length; + that->cod_info->xrpow_max = xrpow_max; + return nbits; +} + + +static void +outOfBitsStrategy(algo_t const* that, const int sfwork[SFBMAX], const int vbrsfmin[SFBMAX], int target) +{ + int wrk[SFBMAX]; + int const dm = sfDepth(sfwork); + int const p = that->cod_info->global_gain; + int nbits; + + /* PART 1 */ + { + int bi = dm / 2; + int bi_ok = -1; + int bu = 0; + int bo = dm; + for (;;) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, bi, p); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + if (nbits <= target) { + bi_ok = bi; + bo = bi - 1; + } + else { + bu = bi + 1; + } + if (bu <= bo) { + bi = (bu + bo) / 2; + } + else { + break; + } + } + if (bi_ok >= 0) { + if (bi != bi_ok) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, bi_ok, p); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + } + return; + } + } + + /* PART 2: */ + { + int bi = (255 + p) / 2; + int bi_ok = -1; + int bu = p; + int bo = 255; + for (;;) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, dm, bi); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + if (nbits <= target) { + bi_ok = bi; + bo = bi - 1; + } + else { + bu = bi + 1; + } + if (bu <= bo) { + bi = (bu + bo) / 2; + } + else { + break; + } + } + if (bi_ok >= 0) { + if (bi != bi_ok) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, dm, bi_ok); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + } + return; + } + } + + /* fall back to old code, likely to be never called */ + searchGlobalStepsizeMax(that, wrk, vbrsfmin, target); +} + + +static int +reduce_bit_usage(lame_internal_flags * gfc, int gr, int ch +#if 0 + , const FLOAT xr34orig[576], const FLOAT l3_xmin[SFBMAX], int maxbits +#endif + ) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + /* try some better scalefac storage + */ + best_scalefac_store(gfc, gr, ch, &gfc->l3_side); + + /* best huffman_divide may save some bits too + */ + if (cfg->use_best_huffman == 1) + best_huffman_divide(gfc, cod_info); + return cod_info->part2_3_length + cod_info->part2_length; +} + + + + +int +VBR_encode_frame(lame_internal_flags * gfc, const FLOAT xr34orig[2][2][576], + const FLOAT l3_xmin[2][2][SFBMAX], const int max_bits[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfwork_[2][2][SFBMAX]; + int vbrsfmin_[2][2][SFBMAX]; + algo_t that_[2][2]; + int const ngr = cfg->mode_gr; + int const nch = cfg->channels_out; + int max_nbits_ch[2][2] = {{0, 0}, {0 ,0}}; + int max_nbits_gr[2] = {0, 0}; + int max_nbits_fr = 0; + int use_nbits_ch[2][2] = {{MAX_BITS_PER_CHANNEL+1, MAX_BITS_PER_CHANNEL+1} + ,{MAX_BITS_PER_CHANNEL+1, MAX_BITS_PER_CHANNEL+1}}; + int use_nbits_gr[2] = { MAX_BITS_PER_GRANULE+1, MAX_BITS_PER_GRANULE+1 }; + int use_nbits_fr = MAX_BITS_PER_GRANULE+MAX_BITS_PER_GRANULE; + int gr, ch; + int ok, sum_fr; + + /* set up some encoding parameters + */ + for (gr = 0; gr < ngr; ++gr) { + max_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + max_nbits_ch[gr][ch] = max_bits[gr][ch]; + use_nbits_ch[gr][ch] = 0; + max_nbits_gr[gr] += max_bits[gr][ch]; + max_nbits_fr += max_bits[gr][ch]; + that_[gr][ch].find = (cfg->full_outer_loop < 0) ? guess_scalefac_x34 : find_scalefac_x34; + that_[gr][ch].gfc = gfc; + that_[gr][ch].cod_info = &gfc->l3_side.tt[gr][ch]; + that_[gr][ch].xr34orig = xr34orig[gr][ch]; + if (that_[gr][ch].cod_info->block_type == SHORT_TYPE) { + that_[gr][ch].alloc = short_block_constrain; + } + else { + that_[gr][ch].alloc = long_block_constrain; + } + } /* for ch */ + } + /* searches scalefactors + */ + for (gr = 0; gr < ngr; ++gr) { + for (ch = 0; ch < nch; ++ch) { + if (max_bits[gr][ch] > 0) { + algo_t *that = &that_[gr][ch]; + int *sfwork = sfwork_[gr][ch]; + int *vbrsfmin = vbrsfmin_[gr][ch]; + int vbrmax; + + vbrmax = block_sf(that, l3_xmin[gr][ch], sfwork, vbrsfmin); + that->alloc(that, sfwork, vbrsfmin, vbrmax); + bitcount(that); + } + else { + /* xr contains no energy + * l3_enc, our encoding data, will be quantized to zero + * continue with next channel + */ + } + } /* for ch */ + } + /* encode 'as is' + */ + use_nbits_fr = 0; + for (gr = 0; gr < ngr; ++gr) { + use_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + algo_t const *that = &that_[gr][ch]; + if (max_bits[gr][ch] > 0) { + memset(&that->cod_info->l3_enc[0], 0, sizeof(that->cod_info->l3_enc)); + (void) quantizeAndCountBits(that); + } + else { + /* xr contains no energy + * l3_enc, our encoding data, will be quantized to zero + * continue with next channel + */ + } + use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch); + use_nbits_gr[gr] += use_nbits_ch[gr][ch]; + } /* for ch */ + use_nbits_fr += use_nbits_gr[gr]; + } + + /* check bit constrains + */ + if (use_nbits_fr <= max_nbits_fr) { + ok = 1; + for (gr = 0; gr < ngr; ++gr) { + if (use_nbits_gr[gr] > MAX_BITS_PER_GRANULE) { + /* violates the rule that every granule has to use no more + * bits than MAX_BITS_PER_GRANULE + */ + ok = 0; + } + for (ch = 0; ch < nch; ++ch) { + if (use_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + /* violates the rule that every gr_ch has to use no more + * bits than MAX_BITS_PER_CHANNEL + * + * This isn't explicitly stated in the ISO docs, but the + * part2_3_length field has only 12 bits, that makes it + * up to a maximum size of 4095 bits!!! + */ + ok = 0; + } + } + } + if (ok) { + return use_nbits_fr; + } + } + + /* OK, we are in trouble and have to define how many bits are + * to be used for each granule + */ + { + ok = 1; + sum_fr = 0; + + for (gr = 0; gr < ngr; ++gr) { + max_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + if (use_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][ch] = MAX_BITS_PER_CHANNEL; + } + else { + max_nbits_ch[gr][ch] = use_nbits_ch[gr][ch]; + } + max_nbits_gr[gr] += max_nbits_ch[gr][ch]; + } + if (max_nbits_gr[gr] > MAX_BITS_PER_GRANULE) { + float f[2] = {0.0f, 0.0f}, s = 0.0f; + for (ch = 0; ch < nch; ++ch) { + if (max_nbits_ch[gr][ch] > 0) { + f[ch] = sqrt(sqrt(max_nbits_ch[gr][ch])); + s += f[ch]; + } + else { + f[ch] = 0; + } + } + for (ch = 0; ch < nch; ++ch) { + if (s > 0) { + max_nbits_ch[gr][ch] = MAX_BITS_PER_GRANULE * f[ch] / s; + } + else { + max_nbits_ch[gr][ch] = 0; + } + } + if (nch > 1) { + if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32) { + max_nbits_ch[gr][1] += max_nbits_ch[gr][0]; + max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32; + max_nbits_ch[gr][0] = use_nbits_ch[gr][0] + 32; + } + if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32) { + max_nbits_ch[gr][0] += max_nbits_ch[gr][1]; + max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32; + max_nbits_ch[gr][1] = use_nbits_ch[gr][1] + 32; + } + if (max_nbits_ch[gr][0] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][0] = MAX_BITS_PER_CHANNEL; + } + if (max_nbits_ch[gr][1] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][1] = MAX_BITS_PER_CHANNEL; + } + } + max_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + max_nbits_gr[gr] += max_nbits_ch[gr][ch]; + } + } + sum_fr += max_nbits_gr[gr]; + } + if (sum_fr > max_nbits_fr) { + { + float f[2] = {0.0f, 0.0f}, s = 0.0f; + for (gr = 0; gr < ngr; ++gr) { + if (max_nbits_gr[gr] > 0) { + f[gr] = sqrt(max_nbits_gr[gr]); + s += f[gr]; + } + else { + f[gr] = 0; + } + } + for (gr = 0; gr < ngr; ++gr) { + if (s > 0) { + max_nbits_gr[gr] = max_nbits_fr * f[gr] / s; + } + else { + max_nbits_gr[gr] = 0; + } + } + } + if (ngr > 1) { + if (max_nbits_gr[0] > use_nbits_gr[0] + 125) { + max_nbits_gr[1] += max_nbits_gr[0]; + max_nbits_gr[1] -= use_nbits_gr[0] + 125; + max_nbits_gr[0] = use_nbits_gr[0] + 125; + } + if (max_nbits_gr[1] > use_nbits_gr[1] + 125) { + max_nbits_gr[0] += max_nbits_gr[1]; + max_nbits_gr[0] -= use_nbits_gr[1] + 125; + max_nbits_gr[1] = use_nbits_gr[1] + 125; + } + for (gr = 0; gr < ngr; ++gr) { + if (max_nbits_gr[gr] > MAX_BITS_PER_GRANULE) { + max_nbits_gr[gr] = MAX_BITS_PER_GRANULE; + } + } + } + for (gr = 0; gr < ngr; ++gr) { + float f[2] = {0.0f, 0.0f}, s = 0.0f; + for (ch = 0; ch < nch; ++ch) { + if (max_nbits_ch[gr][ch] > 0) { + f[ch] = sqrt(max_nbits_ch[gr][ch]); + s += f[ch]; + } + else { + f[ch] = 0; + } + } + for (ch = 0; ch < nch; ++ch) { + if (s > 0) { + max_nbits_ch[gr][ch] = max_nbits_gr[gr] * f[ch] / s; + } + else { + max_nbits_ch[gr][ch] = 0; + } + } + if (nch > 1) { + if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32) { + max_nbits_ch[gr][1] += max_nbits_ch[gr][0]; + max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32; + max_nbits_ch[gr][0] = use_nbits_ch[gr][0] + 32; + } + if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32) { + max_nbits_ch[gr][0] += max_nbits_ch[gr][1]; + max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32; + max_nbits_ch[gr][1] = use_nbits_ch[gr][1] + 32; + } + for (ch = 0; ch < nch; ++ch) { + if (max_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][ch] = MAX_BITS_PER_CHANNEL; + } + } + } + } + } + /* sanity check */ + sum_fr = 0; + for (gr = 0; gr < ngr; ++gr) { + int sum_gr = 0; + for (ch = 0; ch < nch; ++ch) { + sum_gr += max_nbits_ch[gr][ch]; + if (max_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + ok = 0; + } + } + sum_fr += sum_gr; + if (sum_gr > MAX_BITS_PER_GRANULE) { + ok = 0; + } + } + if (sum_fr > max_nbits_fr) { + ok = 0; + } + if (!ok) { + /* we must have done something wrong, fallback to 'on_pe' based constrain */ + for (gr = 0; gr < ngr; ++gr) { + for (ch = 0; ch < nch; ++ch) { + max_nbits_ch[gr][ch] = max_bits[gr][ch]; + } + } + } + } + + /* we already called the 'best_scalefac_store' function, so we need to reset some + * variables before we can do it again. + */ + for (ch = 0; ch < nch; ++ch) { + gfc->l3_side.scfsi[ch][0] = 0; + gfc->l3_side.scfsi[ch][1] = 0; + gfc->l3_side.scfsi[ch][2] = 0; + gfc->l3_side.scfsi[ch][3] = 0; + } + for (gr = 0; gr < ngr; ++gr) { + for (ch = 0; ch < nch; ++ch) { + gfc->l3_side.tt[gr][ch].scalefac_compress = 0; + } + } + + /* alter our encoded data, until it fits into the target bitrate + */ + use_nbits_fr = 0; + for (gr = 0; gr < ngr; ++gr) { + use_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + algo_t const *that = &that_[gr][ch]; + use_nbits_ch[gr][ch] = 0; + if (max_bits[gr][ch] > 0) { + int *sfwork = sfwork_[gr][ch]; + int const *vbrsfmin = vbrsfmin_[gr][ch]; + cutDistribution(sfwork, sfwork, that->cod_info->global_gain); + outOfBitsStrategy(that, sfwork, vbrsfmin, max_nbits_ch[gr][ch]); + } + use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch); + assert(use_nbits_ch[gr][ch] <= max_nbits_ch[gr][ch]); + use_nbits_gr[gr] += use_nbits_ch[gr][ch]; + } /* for ch */ + use_nbits_fr += use_nbits_gr[gr]; + } + + /* check bit constrains, but it should always be ok, iff there are no bugs ;-) + */ + if (use_nbits_fr <= max_nbits_fr) { + return use_nbits_fr; + } + + ERRORF(gfc, "INTERNAL ERROR IN VBR NEW CODE (1313), please send bug report\n" + "maxbits=%d usedbits=%d\n", max_nbits_fr, use_nbits_fr); + exit(-1); +} diff --git a/pkg/lame/clame/vbrquantize.h b/pkg/lame/clame/vbrquantize.h new file mode 100644 index 0000000..1c0d18f --- /dev/null +++ b/pkg/lame/clame/vbrquantize.h @@ -0,0 +1,28 @@ +/* + * MP3 VBR quantization + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_VBRQUANTIZE_H +#define LAME_VBRQUANTIZE_H + +int VBR_encode_frame(lame_internal_flags * gfc, const FLOAT xr34orig[2][2][576], + const FLOAT l3_xmin[2][2][SFBMAX], const int maxbits[2][2]); + +#endif /* LAME_VBRQUANTIZE_H */ diff --git a/pkg/lame/clame/version.c b/pkg/lame/clame/version.c new file mode 100644 index 0000000..2943406 --- /dev/null +++ b/pkg/lame/clame/version.c @@ -0,0 +1,254 @@ +/* + * Version numbering for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*! + \file version.c + \brief Version numbering for LAME. + + Contains functions which describe the version of LAME. + + \author A.L. Faber + \version \$Id: version.c,v 1.34 2011/11/18 09:51:02 robert Exp $ + \ingroup libmp3lame +*/ + + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" + +#include "version.h" /* macros of version numbers */ + + + + + +/*! Get the LAME version string. */ +/*! + \param void + \return a pointer to a string which describes the version of LAME. +*/ +const char * +get_lame_version(void) +{ /* primary to write screen reports */ + /* Here we can also add informations about compile time configurations */ + +#if LAME_ALPHA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " " + "(alpha " STR(LAME_PATCH_VERSION) ", " __DATE__ " " __TIME__ ")"; +#elif LAME_BETA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " " + "(beta " STR(LAME_PATCH_VERSION) ", " __DATE__ ")"; +#elif LAME_RELEASE_VERSION && (LAME_PATCH_VERSION > 0) + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) "." STR(LAME_PATCH_VERSION); +#else + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION); +#endif + + return str; +} + + +/*! Get the short LAME version string. */ +/*! + It's mainly for inclusion into the MP3 stream. + + \param void + \return a pointer to the short version of the LAME version string. +*/ +const char * +get_lame_short_version(void) +{ + /* adding date and time to version string makes it harder for output + validation */ + +#if LAME_ALPHA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " (alpha " STR(LAME_PATCH_VERSION) ")"; +#elif LAME_BETA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " (beta " STR(LAME_PATCH_VERSION) ")"; +#elif LAME_RELEASE_VERSION && (LAME_PATCH_VERSION > 0) + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) "." STR(LAME_PATCH_VERSION); +#else + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION); +#endif + + return str; +} + +/*! Get the _very_ short LAME version string. */ +/*! + It's used in the LAME VBR tag only. + + \param void + \return a pointer to the short version of the LAME version string. +*/ +const char * +get_lame_very_short_version(void) +{ + /* adding date and time to version string makes it harder for output + validation */ +#if LAME_ALPHA_VERSION +#define P "a" +#elif LAME_BETA_VERSION +#define P "b" +#elif LAME_RELEASE_VERSION && (LAME_PATCH_VERSION > 0) +#define P "r" +#else +#define P " " +#endif + static /*@observer@ */ const char *const str = +#if (LAME_PATCH_VERSION > 0) + "LAME" STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) P STR(LAME_PATCH_VERSION) +#else + "LAME" STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) P +#endif + ; + return str; +} + +/*! Get the _very_ short LAME version string. */ +/*! + It's used in the LAME VBR tag only, limited to 9 characters max. + Due to some 3rd party HW/SW decoders, it has to start with LAME. + + \param void + \return a pointer to the short version of the LAME version string. + */ +const char* +get_lame_tag_encoder_short_version(void) +{ + static /*@observer@ */ const char *const str = + /* FIXME: new scheme / new version counting / drop versioning here ? */ + "LAME" STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) P + ; + return str; +} + +/*! Get the version string for GPSYCHO. */ +/*! + \param void + \return a pointer to a string which describes the version of GPSYCHO. +*/ +const char * +get_psy_version(void) +{ +#if PSY_ALPHA_VERSION > 0 + static /*@observer@ */ const char *const str = + STR(PSY_MAJOR_VERSION) "." STR(PSY_MINOR_VERSION) + " (alpha " STR(PSY_ALPHA_VERSION) ", " __DATE__ " " __TIME__ ")"; +#elif PSY_BETA_VERSION > 0 + static /*@observer@ */ const char *const str = + STR(PSY_MAJOR_VERSION) "." STR(PSY_MINOR_VERSION) + " (beta " STR(PSY_BETA_VERSION) ", " __DATE__ ")"; +#else + static /*@observer@ */ const char *const str = + STR(PSY_MAJOR_VERSION) "." STR(PSY_MINOR_VERSION); +#endif + + return str; +} + + +/*! Get the URL for the LAME website. */ +/*! + \param void + \return a pointer to a string which is a URL for the LAME website. +*/ +const char * +get_lame_url(void) +{ + static /*@observer@ */ const char *const str = LAME_URL; + + return str; +} + + +/*! Get the numerical representation of the version. */ +/*! + Writes the numerical representation of the version of LAME and + GPSYCHO into lvp. + + \param lvp +*/ +void +get_lame_version_numerical(lame_version_t * lvp) +{ + static /*@observer@ */ const char *const features = ""; /* obsolete */ + + /* generic version */ + lvp->major = LAME_MAJOR_VERSION; + lvp->minor = LAME_MINOR_VERSION; +#if LAME_ALPHA_VERSION + lvp->alpha = LAME_PATCH_VERSION; + lvp->beta = 0; +#elif LAME_BETA_VERSION + lvp->alpha = 0; + lvp->beta = LAME_PATCH_VERSION; +#else + lvp->alpha = 0; + lvp->beta = 0; +#endif + + /* psy version */ + lvp->psy_major = PSY_MAJOR_VERSION; + lvp->psy_minor = PSY_MINOR_VERSION; + lvp->psy_alpha = PSY_ALPHA_VERSION; + lvp->psy_beta = PSY_BETA_VERSION; + + /* compile time features */ + /*@-mustfree@ */ + lvp->features = features; + /*@=mustfree@ */ +} + + +const char * +get_lame_os_bitness(void) +{ + static /*@observer@ */ const char *const strXX = ""; + static /*@observer@ */ const char *const str32 = "32bits"; + static /*@observer@ */ const char *const str64 = "64bits"; + + switch (sizeof(void *)) { + case 4: + return str32; + + case 8: + return str64; + + default: + return strXX; + } +} + +/* end of version.c */ diff --git a/pkg/lame/clame/version.h b/pkg/lame/clame/version.h new file mode 100644 index 0000000..f5fef50 --- /dev/null +++ b/pkg/lame/clame/version.h @@ -0,0 +1,68 @@ +/* + * Version numbering for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_VERSION_H +#define LAME_VERSION_H + + +/* + * To make a string from a token, use the # operator: + */ +#ifndef STR +# define __STR(x) #x +# define STR(x) __STR(x) +#endif + +# define LAME_URL "http://lame.sf.net" + + +# define LAME_MAJOR_VERSION 3 /* Major version number */ +# define LAME_MINOR_VERSION 100 /* Minor version number */ +# define LAME_TYPE_VERSION 2 /* 0:alpha 1:beta 2:release */ +# define LAME_PATCH_VERSION 0 /* Patch level */ +# define LAME_ALPHA_VERSION (LAME_TYPE_VERSION==0) +# define LAME_BETA_VERSION (LAME_TYPE_VERSION==1) +# define LAME_RELEASE_VERSION (LAME_TYPE_VERSION==2) + +# define PSY_MAJOR_VERSION 1 /* Major version number */ +# define PSY_MINOR_VERSION 0 /* Minor version number */ +# define PSY_ALPHA_VERSION 0 /* Set number if this is an alpha version, otherwise zero */ +# define PSY_BETA_VERSION 0 /* Set number if this is a beta version, otherwise zero */ + +#if LAME_ALPHA_VERSION +#define LAME_PATCH_LEVEL_STRING " alpha " STR(LAME_PATCH_VERSION) +#endif +#if LAME_BETA_VERSION +#define LAME_PATCH_LEVEL_STRING " beta " STR(LAME_PATCH_VERSION) +#endif +#if LAME_RELEASE_VERSION +#if LAME_PATCH_VERSION +#define LAME_PATCH_LEVEL_STRING " release " STR(LAME_PATCH_VERSION) +#else +#define LAME_PATCH_LEVEL_STRING "" +#endif +#endif + +# define LAME_VERSION_STRING STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) LAME_PATCH_LEVEL_STRING + +#endif /* LAME_VERSION_H */ + +/* End of version.h */ diff --git a/pkg/lame/clame/xmm_quantize_sub.c b/pkg/lame/clame/xmm_quantize_sub.c new file mode 100644 index 0000000..d68f761 --- /dev/null +++ b/pkg/lame/clame/xmm_quantize_sub.c @@ -0,0 +1,240 @@ +/* + * MP3 quantization, intrinsics functions + * + * Copyright (c) 2005-2006 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "lame_intrin.h" + + + +#ifdef HAVE_XMMINTRIN_H + +#include + +typedef union { + int32_t _i_32[4]; /* unions are initialized by its first member */ + float _float[4]; + __m128 _m128; +} vecfloat_union; + +#define TRI_SIZE (5-1) /* 1024 = 4**5 */ +static const FLOAT costab[TRI_SIZE * 2] = { + 9.238795325112867e-01, 3.826834323650898e-01, + 9.951847266721969e-01, 9.801714032956060e-02, + 9.996988186962042e-01, 2.454122852291229e-02, + 9.999811752826011e-01, 6.135884649154475e-03 +}; + + +/* make sure functions with SSE instructions maintain their own properly aligned stack */ +#if defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2))) +#define SSE_FUNCTION __attribute__((force_align_arg_pointer)) +#else +#define SSE_FUNCTION +#endif + + +SSE_FUNCTION void +init_xrpow_core_sse(gr_info * const cod_info, FLOAT xrpow[576], int upper, FLOAT * sum) +{ + int i; + float tmp_max = 0; + float tmp_sum = 0; + int upper4 = (upper / 4) * 4; + int rest = upper-upper4; + + const vecfloat_union fabs_mask = {{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }}; + const __m128 vec_fabs_mask = _mm_loadu_ps(&fabs_mask._float[0]); + vecfloat_union vec_xrpow_max; + vecfloat_union vec_sum; + vecfloat_union vec_tmp; + + _mm_prefetch((char *) cod_info->xr, _MM_HINT_T0); + _mm_prefetch((char *) xrpow, _MM_HINT_T0); + + vec_xrpow_max._m128 = _mm_set_ps1(0); + vec_sum._m128 = _mm_set_ps1(0); + + for (i = 0; i < upper4; i += 4) { + vec_tmp._m128 = _mm_loadu_ps(&(cod_info->xr[i])); /* load */ + vec_tmp._m128 = _mm_and_ps(vec_tmp._m128, vec_fabs_mask); /* fabs */ + vec_sum._m128 = _mm_add_ps(vec_sum._m128, vec_tmp._m128); + vec_tmp._m128 = _mm_sqrt_ps(_mm_mul_ps(vec_tmp._m128, _mm_sqrt_ps(vec_tmp._m128))); + vec_xrpow_max._m128 = _mm_max_ps(vec_xrpow_max._m128, vec_tmp._m128); /* retrieve max */ + _mm_storeu_ps(&(xrpow[i]), vec_tmp._m128); /* store into xrpow[] */ + } + vec_tmp._m128 = _mm_set_ps1(0); + switch (rest) { + case 3: vec_tmp._float[2] = cod_info->xr[upper4+2]; + case 2: vec_tmp._float[1] = cod_info->xr[upper4+1]; + case 1: vec_tmp._float[0] = cod_info->xr[upper4+0]; + vec_tmp._m128 = _mm_and_ps(vec_tmp._m128, vec_fabs_mask); /* fabs */ + vec_sum._m128 = _mm_add_ps(vec_sum._m128, vec_tmp._m128); + vec_tmp._m128 = _mm_sqrt_ps(_mm_mul_ps(vec_tmp._m128, _mm_sqrt_ps(vec_tmp._m128))); + vec_xrpow_max._m128 = _mm_max_ps(vec_xrpow_max._m128, vec_tmp._m128); /* retrieve max */ + switch (rest) { + case 3: xrpow[upper4+2] = vec_tmp._float[2]; + case 2: xrpow[upper4+1] = vec_tmp._float[1]; + case 1: xrpow[upper4+0] = vec_tmp._float[0]; + default: + break; + } + default: + break; + } + tmp_sum = vec_sum._float[0] + vec_sum._float[1] + vec_sum._float[2] + vec_sum._float[3]; + { + float ma = vec_xrpow_max._float[0] > vec_xrpow_max._float[1] + ? vec_xrpow_max._float[0] : vec_xrpow_max._float[1]; + float mb = vec_xrpow_max._float[2] > vec_xrpow_max._float[3] + ? vec_xrpow_max._float[2] : vec_xrpow_max._float[3]; + tmp_max = ma > mb ? ma : mb; + } + cod_info->xrpow_max = tmp_max; + *sum = tmp_sum; +} + + +SSE_FUNCTION static void +store4(__m128 v, float* f0, float* f1, float* f2, float* f3) +{ + vecfloat_union r; + r._m128 = v; + *f0 = r._float[0]; + *f1 = r._float[1]; + *f2 = r._float[2]; + *f3 = r._float[3]; +} + + +SSE_FUNCTION void +fht_SSE2(FLOAT * fz, int n) +{ + const FLOAT *tri = costab; + int k4; + FLOAT *fi, *gi; + FLOAT const *fn; + + n <<= 1; /* to get BLKSIZE, because of 3DNow! ASM routine */ + fn = fz + n; + k4 = 4; + do { + FLOAT s1, c1; + int i, k1, k2, k3, kx; + kx = k4 >> 1; + k1 = k4; + k2 = k4 << 1; + k3 = k2 + k1; + k4 = k2 << 1; + fi = fz; + gi = fi + kx; + do { + FLOAT f0, f1, f2, f3; + f1 = fi[0] - fi[k1]; + f0 = fi[0] + fi[k1]; + f3 = fi[k2] - fi[k3]; + f2 = fi[k2] + fi[k3]; + fi[k2] = f0 - f2; + fi[0] = f0 + f2; + fi[k3] = f1 - f3; + fi[k1] = f1 + f3; + f1 = gi[0] - gi[k1]; + f0 = gi[0] + gi[k1]; + f3 = SQRT2 * gi[k3]; + f2 = SQRT2 * gi[k2]; + gi[k2] = f0 - f2; + gi[0] = f0 + f2; + gi[k3] = f1 - f3; + gi[k1] = f1 + f3; + gi += k4; + fi += k4; + } while (fi < fn); + c1 = tri[0]; + s1 = tri[1]; + for (i = 1; i < kx; i++) { + __m128 v_s2; + __m128 v_c2; + __m128 v_c1; + __m128 v_s1; + FLOAT c2, s2, s1_2 = s1+s1; + c2 = 1 - s1_2 * s1; + s2 = s1_2 * c1; + fi = fz + i; + gi = fz + k1 - i; + v_c1 = _mm_set_ps1(c1); + v_s1 = _mm_set_ps1(s1); + v_c2 = _mm_set_ps1(c2); + v_s2 = _mm_set_ps1(s2); + { + static const vecfloat_union sign_mask = {{0x80000000,0,0,0}}; + v_c1 = _mm_xor_ps(sign_mask._m128, v_c1); /* v_c1 := {-c1, +c1, +c1, +c1} */ + } + { + static const vecfloat_union sign_mask = {{0,0x80000000,0,0}}; + v_s1 = _mm_xor_ps(sign_mask._m128, v_s1); /* v_s1 := {+s1, -s1, +s1, +s1} */ + } + { + static const vecfloat_union sign_mask = {{0,0,0x80000000,0x80000000}}; + v_c2 = _mm_xor_ps(sign_mask._m128, v_c2); /* v_c2 := {+c2, +c2, -c2, -c2} */ + } + do { + __m128 p, q, r; + + q = _mm_setr_ps(fi[k1], fi[k3], gi[k1], gi[k3]); /* Q := {fi_k1,fi_k3,gi_k1,gi_k3}*/ + p = _mm_mul_ps(_mm_set_ps1(s2), q); /* P := s2 * Q */ + q = _mm_mul_ps(v_c2, q); /* Q := c2 * Q */ + q = _mm_shuffle_ps(q, q, _MM_SHUFFLE(1,0,3,2)); /* Q := {-c2*gi_k1,-c2*gi_k3,c2*fi_k1,c2*fi_k3} */ + p = _mm_add_ps(p, q); + + r = _mm_setr_ps(gi[0], gi[k2], fi[0], fi[k2]); /* R := {gi_0,gi_k2,fi_0,fi_k2} */ + q = _mm_sub_ps(r, p); /* Q := {gi_0-p0,gi_k2-p1,fi_0-p2,fi_k2-p3} */ + r = _mm_add_ps(r, p); /* R := {gi_0+p0,gi_k2+p1,fi_0+p2,fi_k2+p3} */ + p = _mm_shuffle_ps(q, r, _MM_SHUFFLE(2,0,2,0)); /* P := {q0,q2,r0,r2} */ + p = _mm_shuffle_ps(p, p, _MM_SHUFFLE(3,1,2,0)); /* P := {q0,r0,q2,r2} */ + q = _mm_shuffle_ps(q, r, _MM_SHUFFLE(3,1,3,1)); /* Q := {q1,q3,r1,r3} */ + r = _mm_mul_ps(v_c1, q); + q = _mm_mul_ps(v_s1, q); + q = _mm_shuffle_ps(q, q, _MM_SHUFFLE(0,1,2,3)); /* Q := {q3,q2,q1,q0} */ + q = _mm_add_ps(q, r); + + store4(_mm_sub_ps(p, q), &gi[k3], &gi[k2], &fi[k3], &fi[k2]); + store4(_mm_add_ps(p, q), &gi[k1], &gi[ 0], &fi[k1], &fi[ 0]); + + gi += k4; + fi += k4; + } while (fi < fn); + c2 = c1; + c1 = c2 * tri[0] - s1 * tri[1]; + s1 = c2 * tri[1] + s1 * tri[0]; + } + tri += 2; + } while (k4 < n); +} + +#endif /* HAVE_XMMINTRIN_H */ + diff --git a/pkg/lame/lame.go b/pkg/lame/lame.go new file mode 100644 index 0000000..4129ab0 --- /dev/null +++ b/pkg/lame/lame.go @@ -0,0 +1,239 @@ +package lame + +// http://www.leidinger.net/lame/doxy/html/lame_8h-source.html + +/* +#cgo CFLAGS: -DHAVE_CONFIG_H -I./clame +#cgo LDFLAGS: -lm +#include "lame.h" +*/ +import "C" + +import ( + "runtime" + "unsafe" +) + +type Handle *C.struct_lame_global_struct + +const ( + STEREO = C.STEREO + JOINT_STEREO = C.JOINT_STEREO + DUAL_CHANNEL = C.DUAL_CHANNEL /* LAME doesn't supports this! */ + MONO = C.MONO + NOT_SET = C.NOT_SET + MAX_INDICATOR = C.MAX_INDICATOR + BIT_DEPTH = 16 + + VBR_OFF = C.vbr_off + VBR_RH = C.vbr_rh + VBR_ABR = C.vbr_abr + VBR_MTRH = C.vbr_mtrh + VBR_DEFAULT = C.vbr_default + + MAX_FRAME_SIZE = 2880 +) + +const ( + ABR_8 = C.ABR_8 + ABR_320 = C.ABR_320 + V9 = C.V9 + VBR_10 = C.VBR_10 + V8 = C.V8 + VBR_20 = C.VBR_20 + V7 = C.V7 + VBR_30 = C.VBR_30 + V6 = C.V6 + VBR_40 = C.VBR_40 + V5 = C.V5 + VBR_50 = C.VBR_50 + V4 = C.V4 + VBR_60 = C.VBR_60 + V3 = C.V3 + VBR_70 = C.VBR_70 + V2 = C.V2 + VBR_80 = C.VBR_80 + V1 = C.V1 + VBR_90 = C.VBR_90 + V0 = C.V0 + VBR_100 = C.VBR_100 +) + +type Encoder struct { + handle Handle + remainder []byte + closed bool +} + +func Init() *Encoder { + handle := C.lame_init() + encoder := &Encoder{handle, make([]byte, 0), false} + runtime.SetFinalizer(encoder, finalize) + return encoder +} + +func (e *Encoder) SetVBR(mode C.vbr_mode) { + C.lame_set_VBR(e.handle, mode) +} + +func (e *Encoder) SetVBRAverageBitRate(averageBitRate int) { + C.lame_set_VBR_mean_bitrate_kbps(e.handle, C.int(averageBitRate)) +} + +func (e *Encoder) SetVBRQuality(quality int) { + C.lame_set_VBR_q(e.handle, C.int(quality)) +} + +func (e *Encoder) SetLowPassFrequency(frequency int) { + // Frequency in Hz + C.lame_set_lowpassfreq(e.handle, C.int(frequency)) +} + +func (e *Encoder) SetNumChannels(num int) { + C.lame_set_num_channels(e.handle, C.int(num)) +} + +func (e *Encoder) SetInSamplerate(sampleRate int) { + C.lame_set_in_samplerate(e.handle, C.int(sampleRate)) +} + +func (e *Encoder) SetBitrate(bitRate int) { + C.lame_set_brate(e.handle, C.int(bitRate)) +} + +func (e *Encoder) SetMode(mode C.MPEG_mode) { + C.lame_set_mode(e.handle, mode) +} + +func (e *Encoder) SetQuality(quality int) { + C.lame_set_quality(e.handle, C.int(quality)) +} + +func (e *Encoder) InitId3Tag() { + C.id3tag_init(e.handle) +} + +func (e *Encoder) SetWriteId3tagAutomatic(automaticWriteTag int) { + C.lame_set_write_id3tag_automatic(e.handle, C.int(automaticWriteTag)) +} + +func (e *Encoder) ID3TagAddV2() { + C.id3tag_add_v2(e.handle) +} + +func (e *Encoder) SetbWriteVbrTag(writeVbrTag int) { + C.lame_set_bWriteVbrTag(e.handle, C.int(writeVbrTag)) +} + +func (e *Encoder) GetLametagFrame() []byte { + tagFrame := make([]byte, MAX_FRAME_SIZE) + tagFrameLen := C.lame_get_lametag_frame(e.handle, (*C.uchar)(unsafe.Pointer(&tagFrame[0])), C.size_t(len(tagFrame))) + + return tagFrame[0:tagFrameLen] +} + +func (e *Encoder) InitParams() int { + retcode := C.lame_init_params(e.handle) + return int(retcode) +} + +func (e *Encoder) NumChannels() int { + n := C.lame_get_num_channels(e.handle) + return int(n) +} + +func (e *Encoder) Bitrate() int { + br := C.lame_get_brate(e.handle) + return int(br) +} + +func (e *Encoder) Mode() int { + m := C.lame_get_mode(e.handle) + return int(m) +} + +func (e *Encoder) Quality() int { + q := C.lame_get_quality(e.handle) + return int(q) +} + +func (e *Encoder) InSamplerate() int { + sr := C.lame_get_in_samplerate(e.handle) + return int(sr) +} + +func (e *Encoder) Encode(buf []byte) []byte { + + if len(e.remainder) > 0 { + buf = append(e.remainder, buf...) + } + + if len(buf) == 0 { + return make([]byte, 0) + } + + blockAlign := BIT_DEPTH / 8 * e.NumChannels() + + remainBytes := len(buf) % blockAlign + if remainBytes > 0 { + e.remainder = buf[len(buf)-remainBytes : len(buf)] + buf = buf[0 : len(buf)-remainBytes] + } else { + e.remainder = make([]byte, 0) + } + + numSamples := len(buf) / blockAlign + estimatedSize := int(1.25*float64(numSamples) + 7200) + out := make([]byte, estimatedSize) + + cBuf := (*C.short)(unsafe.Pointer(&buf[0])) + cOut := (*C.uchar)(unsafe.Pointer(&out[0])) + + var bytesOut C.int + + if e.NumChannels() == 1 { + bytesOut = C.int(C.lame_encode_buffer( + e.handle, + cBuf, + nil, + C.int(numSamples), + cOut, + C.int(estimatedSize), + )) + } else { + bytesOut = C.int(C.lame_encode_buffer_interleaved( + e.handle, + cBuf, + C.int(numSamples), + cOut, + C.int(estimatedSize), + )) + } + return out[0:bytesOut] + +} + +func (e *Encoder) Flush() []byte { + estimatedSize := 7200 + out := make([]byte, estimatedSize) + cOut := (*C.uchar)(unsafe.Pointer(&out[0])) + bytesOut := C.int(C.lame_encode_flush( + e.handle, + cOut, + C.int(estimatedSize), + )) + + return out[0:bytesOut] +} + +func (e *Encoder) Close() { + if e.closed { + return + } + C.lame_close(e.handle) + e.closed = true +} + +func finalize(e *Encoder) { + e.Close() +} diff --git a/pkg/lame/writer.go b/pkg/lame/writer.go new file mode 100644 index 0000000..6f6b59e --- /dev/null +++ b/pkg/lame/writer.go @@ -0,0 +1,41 @@ +package lame + +import ( + "io" +) + +type LameWriter struct { + output io.Writer + Encoder *Encoder + EncodedChunkSize int +} + +func NewWriter(out io.Writer) *LameWriter { + writer := &LameWriter{out, Init(), 0} + return writer +} + +func (lw *LameWriter) Write(p []byte) (int, error) { + // fmt.Println("lame Write len:", len(p)) + out := lw.Encoder.Encode(p) + lw.EncodedChunkSize = len(out) + + if lw.EncodedChunkSize > 0 { + _, err := lw.output.Write(out) + if err != nil { + return 0, err + } + } + + return len(p), nil +} + +func (lw *LameWriter) Close() error { + out := lw.Encoder.Flush() + if len(out) == 0 { + return nil + } + lw.Encoder.Close() + _, err := lw.output.Write(out) + return err +} diff --git a/pkg/lame/z_link_lame_c.c b/pkg/lame/z_link_lame_c.c new file mode 100644 index 0000000..830401d --- /dev/null +++ b/pkg/lame/z_link_lame_c.c @@ -0,0 +1,21 @@ +#include "./clame/reservoir.c" +#include "./clame/bitstream.c" +#include "./clame/newmdct.c" +#include "./clame/gain_analysis.c" +#include "./clame/version.c" +#include "./clame/mpglib_interface.c" +#include "./clame/xmm_quantize_sub.c" +#include "./clame/vbrquantize.c" +#include "./clame/quantize_pvt.c" +#include "./clame/VbrTag.c" +#include "./clame/encoder.c" +#include "./clame/quantize.c" +#include "./clame/takehiro.c" +#include "./clame/fft.c" +#include "./clame/lame.c" +#include "./clame/set_get.c" +#include "./clame/id3tag.c" +#include "./clame/tables.c" +#include "./clame/util.c" +#include "./clame/psymodel.c" +#include "./clame/presets.c" diff --git a/pkg/silk/csilk/Decoder_Api.c b/pkg/silk/csilk/Decoder_Api.c new file mode 100644 index 0000000..b67207b --- /dev/null +++ b/pkg/silk/csilk/Decoder_Api.c @@ -0,0 +1,80 @@ + +#include +#include +#include +#include "SKP_Silk_SDK_API.h" + +#define MAX_INPUT_FRAMES 5 + +typedef struct silk_handle{ + SKP_SILK_SDK_DecControlStruct dec_ctrl; + SKP_uint8 *dec_state; +} * silk_handle_t; + +struct silk_handle *silk_decoder_init(void) +{ + silk_handle_t handle = calloc(1, sizeof(struct silk_handle)); + if (NULL == handle) + return NULL; + + handle->dec_ctrl.API_sampleRate = 24000; + handle->dec_ctrl.framesPerPacket = 1; + + SKP_int32 dec_size; + SKP_Silk_SDK_Get_Decoder_Size(&dec_size); + + handle->dec_state = calloc(1, dec_size); + if (NULL == handle->dec_state) { + free(handle); + return NULL; + } + + SKP_Silk_SDK_InitDecoder(handle->dec_state); + + return handle; +} + +void silk_decoder_deinit(struct silk_handle *h) { + silk_handle_t handle = (silk_handle_t)h; + + if (handle) { + if (handle->dec_state) { + free(handle->dec_state); + handle->dec_state = NULL; + } + free(handle); + } +} + +int silk_decoder_process(struct silk_handle *h, unsigned char *frame, int frame_size, unsigned char *output_payload, int output_len) +{ + silk_handle_t handle = (silk_handle_t)h; + SKP_int16 *out_ptr = (SKP_int16 *)output_payload; + SKP_int16 len = 0, total_len = 0; + SKP_int32 frame_count = 0; + do { + SKP_Silk_SDK_Decode(handle->dec_state, &handle->dec_ctrl, 0, frame, frame_size, out_ptr, &len); + frame_count++; + out_ptr += len; + total_len += len; + if (frame_count > MAX_INPUT_FRAMES) { + printf("frame_count > MAX_INPUT_FRAMES frame_count %d, total_len %d\n", frame_count, total_len); + out_ptr = (SKP_int16 *)output_payload; + total_len = 0; + frame_count = 0; + } + } while (handle->dec_ctrl.moreInternalDecoderFrames); + + + return total_len * 2; +} + +int silk_decoder_set_sample_rate(struct silk_handle *h, int rate) +{ + silk_handle_t handle = (silk_handle_t)h; + if (handle) { + handle->dec_ctrl.API_sampleRate = rate; + } + + return 0; +} diff --git a/pkg/silk/csilk/SKP_Silk_A2NLSF.c b/pkg/silk/csilk/SKP_Silk_A2NLSF.c new file mode 100644 index 0000000..fd6918f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_A2NLSF.c @@ -0,0 +1,287 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Conversion between prediction filter coefficients and NLSFs */ +/* Requires the order to be an even number */ +/* A piecewise linear approximation maps LSF <-> cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* function are accurate inverses of each other */ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Number of binary divisions */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define QPoly 16 +#define MAX_ITERATIONS_A2NLSF_FIX 30 + +/* Flag for using 2x as many cosine sampling points, reduces the risk of missing a root */ +#define OVERSAMPLE_COSINE_TABLE 0 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +SKP_INLINE void SKP_Silk_A2NLSF_trans_poly( + SKP_int32 *p, /* I/O Polynomial */ + const SKP_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + SKP_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= SKP_LSHIFT( p[ k ], 1 ); + } +} +#if EMBEDDED_ARM<6 +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +SKP_INLINE SKP_int32 SKP_Silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in QPoly */ + SKP_int32 *p, /* I Polynomial, QPoly */ + const SKP_int32 x, /* I Evaluation point, Q12 */ + const SKP_int dd /* I Order */ +) +{ + SKP_int n; + SKP_int32 x_Q16, y32; + + y32 = p[ dd ]; /* QPoly */ + x_Q16 = SKP_LSHIFT( x, 4 ); + for( n = dd - 1; n >= 0; n-- ) { + y32 = SKP_SMLAWW( p[ n ], y32, x_Q16 ); /* QPoly */ + } + return y32; +} +#else +SKP_int32 SKP_Silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in QPoly */ + SKP_int32 *p, /* I Polynomial, QPoly */ + const SKP_int32 x, /* I Evaluation point, Q12 */ + const SKP_int dd /* I Order */ +); +#endif + +SKP_INLINE void SKP_Silk_A2NLSF_init( + const SKP_int32 *a_Q16, + SKP_int32 *P, + SKP_int32 *Q, + const SKP_int dd +) +{ + SKP_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = SKP_LSHIFT( 1, QPoly ); + Q[dd] = SKP_LSHIFT( 1, QPoly ); + for( k = 0; k < dd; k++ ) { +#if( QPoly < 16 ) + P[ k ] = SKP_RSHIFT_ROUND( -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ], 16 - QPoly ); /* QPoly */ + Q[ k ] = SKP_RSHIFT_ROUND( -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ], 16 - QPoly ); /* QPoly */ +#elif( QPoly == 16 ) + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; // QPoly + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; // QPoly +#else + P[ k ] = SKP_LSHIFT( -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ], QPoly - 16 ); /* QPoly */ + Q[ k ] = SKP_LSHIFT( -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ], QPoly - 16 ); /* QPoly */ +#endif + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + SKP_Silk_A2NLSF_trans_poly( P, dd ); + SKP_Silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void SKP_Silk_A2NLSF( + SKP_int *NLSF, /* O Normalized Line Spectral Frequencies, Q15 (0 - (2^15-1)), [d] */ + SKP_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const SKP_int d /* I Filter order (must be even) */ +) +{ + SKP_int i, k, m, dd, root_ix, ffrac; + SKP_int32 xlo, xhi, xmid; + SKP_int32 ylo, yhi, ymid; + SKP_int32 nom, den; + SKP_int32 P[ SKP_Silk_MAX_ORDER_LPC / 2 + 1 ]; + SKP_int32 Q[ SKP_Silk_MAX_ORDER_LPC / 2 + 1 ]; + SKP_int32 *PQ[ 2 ]; + SKP_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = SKP_RSHIFT( d, 1 ); + + SKP_Silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ 0 ]; // Q12 + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + while( 1 ) { + /* Evaluate polynomial */ +#if OVERSAMPLE_COSINE_TABLE + xhi = SKP_Silk_LSFCosTab_FIX_Q12[ k >> 1 ] + + ( ( SKP_Silk_LSFCosTab_FIX_Q12[ ( k + 1 ) >> 1 ] - + SKP_Silk_LSFCosTab_FIX_Q12[ k >> 1 ] ) >> 1 ); /* Q12 */ +#else + xhi = SKP_Silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ +#endif + yhi = SKP_Silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= 0 ) || ( ylo >= 0 && yhi <= 0 ) ) { + /* Binary division */ +#if OVERSAMPLE_COSINE_TABLE + ffrac = -128; +#else + ffrac = -256; +#endif + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = SKP_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = SKP_Silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; +#if OVERSAMPLE_COSINE_TABLE + ffrac = SKP_ADD_RSHIFT( ffrac, 64, m ); +#else + ffrac = SKP_ADD_RSHIFT( ffrac, 128, m ); +#endif + } + } + + /* Interpolate */ + if( SKP_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = SKP_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + SKP_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += SKP_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += SKP_DIV32( ylo, SKP_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } +#if OVERSAMPLE_COSINE_TABLE + NLSF[ root_ix ] = (SKP_int)SKP_min_32( SKP_LSHIFT( (SKP_int32)k, 7 ) + ffrac, SKP_int16_MAX ); +#else + NLSF[ root_ix ] = (SKP_int)SKP_min_32( SKP_LSHIFT( (SKP_int32)k, 8 ) + ffrac, SKP_int16_MAX ); +#endif + + SKP_assert( NLSF[ root_ix ] >= 0 ); + SKP_assert( NLSF[ root_ix ] <= 32767 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ +#if OVERSAMPLE_COSINE_TABLE + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ ( k - 1 ) >> 1 ] + + ( ( SKP_Silk_LSFCosTab_FIX_Q12[ k >> 1 ] - + SKP_Silk_LSFCosTab_FIX_Q12[ ( k - 1 ) >> 1 ] ) >> 1 ); // Q12 +#else + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ k - 1 ]; // Q12 +#endif + ylo = SKP_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + +#if OVERSAMPLE_COSINE_TABLE + if( k > 2 * LSF_COS_TAB_SZ_FIX ) { +#else + if( k > LSF_COS_TAB_SZ_FIX ) { +#endif + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = SKP_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = SKP_SMULBB( k + 1, NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + SKP_Silk_bwexpander_32( a_Q16, d, 65536 - SKP_SMULBB( 10 + i, i ) ); // 10_Q16 = 0.00015 + + SKP_Silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = SKP_Silk_LSFCosTab_FIX_Q12[ 0 ]; // Q12 + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = SKP_Silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/pkg/silk/csilk/SKP_Silk_AsmHelper.h b/pkg/silk/csilk/SKP_Silk_AsmHelper.h new file mode 100644 index 0000000..4e8a69b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_AsmHelper.h @@ -0,0 +1,180 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + * SKP_Silk_AsmHelper.h + * + * + * + * + */ + + +#ifndef _SKP_ASM_HELPER_H_ +#define _SKP_ASM_HELPER_H_ + +// Register bank +#define _REG 0 +#define _DREG 1 + +// Arg registers +#define _R0 0 +#define _R1 1 +#define _R2 2 +#define _R3 3 +#define _R4 4 +// GP registers +#define _R5 5 +#define _R6 6 +#define _R7 7 +#define _R8 8 +#define _SB 9 +#define _SL 10 +// fp and ip registers +#define _FP 11 +#define _IP 12 +// lr and sp registers +#define _SP 13 +#define _LR 14 + + +// Extension register bank +#define _numDReg + +#define _Q0 0 +#define _Q1 1 +#define _Q2 2 +#define _Q3 3 +#define _Q4 4 +#define _Q5 5 +#define _Q6 6 +#define _Q7 7 +#define _Q8 8 +#define _Q9 9 +#define _Q10 10 +#define _Q11 11 +#define _Q12 12 +#define _Q13 13 +#define _Q14 14 +#define _Q15 15 + +#if defined (_WINRT) +#else +#if defined (IPHONE) +#define MACRO .macro +#define END_MACRO .endmacro +#define ARG0_in +#define ARG1_in +#define ARG2_in +#define ARG3_in +#define ARG4_in +#define ARG5_in +#define ARG6_in +#define ARG7_in +#define ARG0 $0 +#define ARG1 $1 +#define ARG2 $2 +#define ARG3 $3 +#define ARG4 $4 +#define ARG5 $5 +#define ARG6 $6 +#define ARG7 $7 +#define RARG0 r$0 +#define RARG1 r$1 +#define QARG0 q$0 +#define QARG1 q$1 + +MACRO CHECK_ABS ARG0_in, ARG1_in + .abs is_abs, ARG1 + .if is_abs==1 + .set ARG0, ARG1 + .else + .set ARG0, -1 + .endif +END_MACRO + +#else +#define MACRO .macro +#define END_MACRO .endm +#define ARG0_in arg0=-1 +#define ARG1_in arg1=-1 +#define ARG2_in arg2=-1 +#define ARG3_in arg3=-1 +#define ARG4_in arg4=-1 +#define ARG5_in arg5=-1 +#define ARG6_in arg6=-1 +#define ARG7_in arg7=-1 +#define ARG0 \arg0 +#define ARG1 \arg1 +#define ARG2 \arg2 +#define ARG3 \arg3 +#define ARG4 \arg4 +#define ARG5 \arg5 +#define ARG6 \arg6 +#define ARG7 \arg7 +#define RARG0 r\arg0 +#define RARG1 r\arg1 +#define QARG0 q\arg0 +#define QARG1 q\arg1 + +MACRO CHECK_ABS ARG0_in, ARG1_in + .set ARG0, ARG1 +END_MACRO +#endif + +MACRO VARDEF ARG0_in, ARG1_in +ARG0 .req ARG1 +END_MACRO + +MACRO VARDEFD ARG0_in, ARG1_in +ARG0 .req ARG1 +END_MACRO + +MACRO VARDEFQ ARG0_in, ARG1_in +ARG0 .req ARG1 +END_MACRO + +MACRO END +END_MACRO + +MACRO EXTERN ARG0_in +END_MACRO + +MACRO ALIGN ARG0_in +.align ARG0 +END_MACRO + +MACRO DATA +.data +END_MACRO + +MACRO EXPORT ARG0_in +.globl ARG0 +END_MACRO + +#endif +#endif diff --git a/pkg/silk/csilk/SKP_Silk_AsmPreproc.h b/pkg/silk/csilk/SKP_Silk_AsmPreproc.h new file mode 100644 index 0000000..d2e47e8 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_AsmPreproc.h @@ -0,0 +1,220 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* SKP_Silk_AsmPreProc.h + * + * General header for all ARM asms uses SigProcLib. + * It contains C preprocessor part and asm preprocessor part. + * C preprocessor part: + * * Interfacing makefile, arch, fpu and neon support + * * Interfacing different symbol styles and asm directives. + * * Interfacing compiling time standard output + * ASM preprocessor part: + * * Defining general asm header/footer for stack/return value + * * Allocating stack for local variables and nasted function + * * Defining simple syntax checking and debugging routines + */ + + +/* + * C preprocessor part + */ +#ifndef _SKP_ASM_PREPROC_H_ +#define _SKP_ASM_PREPROC_H_ + +#include "SKP_Silk_AsmHelper.h" + + +/* Checking compilier __ARMEL__ defines */ +#if !__ARMEL__ && (!defined(NO_ASM)) && (!defined(_WINRT)) +#error Currently SKP_Silk_AsmPreProc only supports little endian. +// above line can be replaced by +// #warning __ARMEL__=0 +// #define NOASM +#endif + +/* Defining macro for different user label prefix. */ +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Remapping register for iphone. */ + +#ifdef IPHONE +# define _fp r7 +# define _r7 r11 +#else +# define _fp fp +# define _r7 r7 +#endif + +/* Checking compiler __ARM_EABI__ defines */ + +#if __ARMEB__ +#define NO_ASM //remove asm optimization for ARM big endian. +#else +#define ARM_LITTLE_ENDIAN +#endif + +/* Interfacing some asm directives to macros*/ +#define GBL .globl + +/* Legacy definition wrapper */ +#ifndef NO_ASM +#if defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5T__) +#define EMBEDDED_ARM 4 +#define EMBEDDED_ARMv4 +#elif defined (__ARM_ARCH_5TE__) || defined (__ARM_ARCH_5TEJ__) +#define EMBEDDED_ARM 5 +#define EMBEDDED_ARMv5 +#elif defined (__ARM_ARCH_6__) ||defined (__ARM_ARCH_6J__) || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) +#define EMBEDDED_ARM 6 +#define EMBEDDED_ARMv6 +#elif defined (__ARM_ARCH_7A__) && defined (__ARM_NEON__) +#define EMBEDDED_ARM 7 +#define EMBEDDED_ARMv6 +#elif defined (__ARM_ARCH_7A__) +#define EMBEDDED_ARM 6 +#define EMBEDDED_ARMv6 +#else +#define EMBEDDED_ARM 0 +#endif +#endif + +#ifdef _WINRT +#define L(a) a +#define LR(a,d) %##d##a + +#define TABLE(L, symbol) symbol +#else +#define L(a) a: +#define LR(a,d) a##d +#define DCD .long +#define DCW .short +#define TABLE(L, symbol) L +#endif + +#ifdef _WINRT +#define streqh strheq +#define strneh strhne +#define strgth strhgt +#define strlth strhlt +#define ldrgtsh ldrshgt +#define ldmgtia ldmiagt +#define ldmgtdb ldmdbgt +#define ldrneh ldrhne +#define ldmltia ldmialt +#endif +/* + * ASM preprocessor part: + */ + +#ifdef _WINRT +#else +// AT&T Format +#if EMBEDDED_ARM >= 7 +.set _ARCH, 7 +#elif EMBEDDED_ARM >= 6 +.set _ARCH, 6 +#elif EMBEDDED_ARM >= 5 // Should be re-considerred as ARMv5 != ARMv5E +.set _ARCH, 5 +#elif EMBEDDED_ARM >= 4 +.set _ARCH, 4 +#else +.set _ARCH, 0 +#endif + +#if NEON +.set _NEON, 1 +#else +.set _NEON, 0 +#endif + +MACRO SKP_TABLE ARG0_in, ARG1_in +SYM(ARG0): +END_MACRO + + + +MACRO SKP_SMLAD ARG0_in, ARG1_in, ARG2_in, ARG3_in +#if EMBEDDED_ARM>=6 + smlad ARG0, ARG1, ARG2, ARG3 +#elif EMBEDDED_ARM>=5 + smlabb ARG0, ARG1, ARG2, ARG3 + smlatt ARG0, ARG1, ARG2, ARG0 +#else + .abort "SKP_SMUAD can't be used for armv4 or lower device.." +#endif +END_MACRO + +MACRO SKP_SMUAD ARG0_in, ARG1_in, ARG2_in +#if EMBEDDED_ARM>=6 + smuad ARG0, ARG1, ARG2 +#elif EMBEDDED_ARM>=5 + smulbb ARG0, ARG1, ARG2 + smlatt ARG0, ARG1, ARG2, ARG0 +#else + .abort "SKP_SMUAD can't be used for armv4 or lower device.." +#endif +END_MACRO + +MACRO SKP_SMLALD ARG0_in, ARG1_in, ARG2_in, ARG3_in +#if EMBEDDED_ARM>=6 + smlald ARG0, ARG1, ARG2, ARG3 +#elif EMBEDDED_ARM>=5 + smlalbb ARG0, ARG1, ARG2, ARG3 + smlaltt ARG0, ARG1, ARG2, ARG3 +#else + .abort "SKP_SMLALD can't be used for armv4 or lower device.." +#endif +END_MACRO + +MACRO SKP_RSHIFT_ROUND ARG0_in, ARG1_in, ARG2_in +#if EMBEDDED_ARM>=4 + mov ARG0, ARG1, asr #(ARG2-1) + add ARG0, ARG0, #1 + mov ARG0, ARG0, asr #1 +#else + .abort "SKP_RSHIFT_ROUND can't be used for armv3 or lower device.." +#endif +END_MACRO + +MACRO ADD_SHIFT ARG0_in, ARG1_in, ARG2_in, ARG3_in, ARG4_in + add ARG0, ARG1, ARG2, ARG3 ARG4 +END_MACRO + +MACRO POST_IR ARG0_in, ARG1_in, ARG2_in, ARG3_in + ARG0 ARG1, [ARG2], ARG3 +END_MACRO + +#endif +#endif //_SKP_ASM_PREPROC_H_ diff --git a/pkg/silk/csilk/SKP_Silk_CNG.c b/pkg/silk/csilk/SKP_Silk_CNG.c new file mode 100644 index 0000000..8d0e6a1 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_CNG.c @@ -0,0 +1,149 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Generates excitation for CNG LPC synthesis */ +SKP_INLINE void SKP_Silk_CNG_exc( + SKP_int16 residual[], /* O CNG residual signal Q0 */ + SKP_int32 exc_buf_Q10[], /* I Random samples buffer Q10 */ + SKP_int32 Gain_Q16, /* I Gain to apply */ + SKP_int length, /* I Length */ + SKP_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + SKP_int32 seed; + SKP_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = SKP_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = SKP_RAND( seed ); + idx = ( SKP_int )( SKP_RSHIFT( seed, 24 ) & exc_mask ); + SKP_assert( idx >= 0 ); + SKP_assert( idx <= CNG_BUF_MASK_MAX ); + residual[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( exc_buf_Q10[ idx ], Gain_Q16 ), 10 ) ); + } + *rand_seed = seed; +} + +void SKP_Silk_CNG_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + SKP_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = SKP_DIV32_16( SKP_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void SKP_Silk_CNG( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O Signal */ + SKP_int length /* I Length of residual */ +) +{ + SKP_int i, subfr; + SKP_int32 tmp_32, Gain_Q26, max_Gain_Q16; + SKP_int16 LPC_buf[ MAX_LPC_ORDER ]; + SKP_int16 CNG_sig[ MAX_FRAME_LENGTH ]; + SKP_Silk_CNG_struct *psCNG; + psCNG = &psDec->sCNG; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + SKP_Silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->vadFlag == NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += SKP_SMULWB( psDec->prevNLSF_Q15[ i ] - psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < NB_SUBFR; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + SKP_memmove( &psCNG->CNG_exc_buf_Q10[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q10, ( NB_SUBFR - 1 ) * psDec->subfr_length * sizeof( SKP_int32 ) ); + SKP_memcpy( psCNG->CNG_exc_buf_Q10, &psDec->exc_Q10[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( SKP_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < NB_SUBFR; i++ ) { + psCNG->CNG_smth_Gain_Q16 += SKP_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost and / or when low speech activity */ + if( psDec->lossCnt ) {//|| psDec->vadFlag == NO_VOICE_ACTIVITY ) { + + /* Generate CNG excitation */ + SKP_Silk_CNG_exc( CNG_sig, psCNG->CNG_exc_buf_Q10, + psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + SKP_Silk_NLSF2A_stable( LPC_buf, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); + + Gain_Q26 = ( SKP_int32 )1 << 26; /* 1.0 */ + + /* Generate CNG signal, by synthesis filtering */ + if( psDec->LPC_order == 16 ) { + SKP_Silk_LPC_synthesis_order16( CNG_sig, LPC_buf, + Gain_Q26, psCNG->CNG_synth_state, CNG_sig, length ); + } else { + SKP_Silk_LPC_synthesis_filter( CNG_sig, LPC_buf, + Gain_Q26, psCNG->CNG_synth_state, CNG_sig, length, psDec->LPC_order ); + } + /* Mix with signal */ + for( i = 0; i < length; i++ ) { + tmp_32 = signal[ i ] + CNG_sig[ i ]; + signal[ i ] = SKP_SAT16( tmp_32 ); + } + } else { + SKP_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( SKP_int32 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c b/pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c new file mode 100644 index 0000000..6a3b35a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c @@ -0,0 +1,120 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +#if HIGH_PASS_INPUT + +#define SKP_RADIANS_CONSTANT_Q19 1482 // 0.45f * 2.0f * 3.14159265359 / 1000 +#define SKP_LOG2_VARIABLE_HP_MIN_FREQ_Q7 809 // log(80) in Q7 + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void SKP_Silk_HP_variable_cutoff_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + SKP_int16 *out, /* O high-pass filtered output signal */ + const SKP_int16 *in /* I input signal */ +) +{ + SKP_int quality_Q15; + SKP_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + SKP_int32 Fc_Q19, r_Q28, r_Q22; + SKP_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + + /*********************************************/ + /* Estimate Low End of Pitch Frequency Range */ + /*********************************************/ + if( psEnc->sCmn.prev_sigtype == SIG_TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = SKP_DIV32_16( SKP_LSHIFT( SKP_MUL( psEnc->sCmn.fs_kHz, 1000 ), 16 ), psEnc->sCmn.prevLag ); + pitch_freq_log_Q7 = SKP_Silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); //0x70 + + /* adjustment based on quality */ + quality_Q15 = psEncCtrl->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = SKP_SUB32( pitch_freq_log_Q7, SKP_SMULWB( SKP_SMULWB( SKP_LSHIFT( quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - SKP_LOG2_VARIABLE_HP_MIN_FREQ_Q7 ) ); + pitch_freq_log_Q7 = SKP_ADD32( pitch_freq_log_Q7, SKP_RSHIFT( SKP_FIX_CONST( 0.6, 15 ) - quality_Q15, 9 ) ); + + //delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; + delta_freq_Q7 = pitch_freq_log_Q7 - SKP_RSHIFT( psEnc->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = SKP_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers */ + delta_freq_Q7 = SKP_LIMIT_32( delta_freq_Q7, -SKP_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SKP_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEnc->variable_HP_smth1_Q15 = SKP_SMLAWB( psEnc->variable_HP_smth1_Q15, + SKP_MUL( SKP_LSHIFT( psEnc->speech_activity_Q8, 1 ), delta_freq_Q7 ), SKP_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + } + /* second smoother */ + psEnc->variable_HP_smth2_Q15 = SKP_SMLAWB( psEnc->variable_HP_smth2_Q15, + psEnc->variable_HP_smth1_Q15 - psEnc->variable_HP_smth2_Q15, SKP_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + psEncCtrl->pitch_freq_low_Hz = SKP_Silk_log2lin( SKP_RSHIFT( psEnc->variable_HP_smth2_Q15, 8 ) ); + + /* limit frequency range */ + psEncCtrl->pitch_freq_low_Hz = SKP_LIMIT_32( psEncCtrl->pitch_freq_low_Hz, + SKP_FIX_CONST( VARIABLE_HP_MIN_FREQ, 0 ), SKP_FIX_CONST( VARIABLE_HP_MAX_FREQ, 0 ) ); + + /********************************/ + /* Compute Filter Coefficients */ + /********************************/ + /* compute cut-off frequency, in radians */ + //Fc_num = (SKP_float)( 0.45f * 2.0f * 3.14159265359 * psEncCtrl->pitch_freq_low_Hz ); + //Fc_denom = (SKP_float)( 1e3f * psEnc->sCmn.fs_kHz ); + SKP_assert( psEncCtrl->pitch_freq_low_Hz <= SKP_int32_MAX / SKP_RADIANS_CONSTANT_Q19 ); + Fc_Q19 = SKP_DIV32_16( SKP_SMULBB( SKP_RADIANS_CONSTANT_Q19, psEncCtrl->pitch_freq_low_Hz ), psEnc->sCmn.fs_kHz ); // range: 3704 - 27787, 11-15 bits + SKP_assert( Fc_Q19 >= 3704 ); + SKP_assert( Fc_Q19 <= 27787 ); + + r_Q28 = SKP_FIX_CONST( 1.0, 28 ) - SKP_MUL( SKP_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + SKP_assert( r_Q28 >= 255347779 ); + SKP_assert( r_Q28 <= 266690872 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = SKP_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + // -r * ( 2 - Fc * Fc ); + r_Q22 = SKP_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = SKP_SMULWW( r_Q22, SKP_SMULWW( Fc_Q19, Fc_Q19 ) - SKP_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = SKP_SMULWW( r_Q22, r_Q22 ); + + /********************************/ + /* High-Pass Filter */ + /********************************/ + SKP_Silk_biquad_alt( in, B_Q28, A_Q28, psEnc->sCmn.In_HP_State, out, psEnc->sCmn.frame_length ); +} + +#endif // HIGH_PASS_INPUT diff --git a/pkg/silk/csilk/SKP_Silk_Inlines.h b/pkg/silk/csilk/SKP_Silk_Inlines.h new file mode 100644 index 0000000..6810e86 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_Inlines.h @@ -0,0 +1,278 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*! \file SKP_Silk_Inlines.h + * \brief SKP_Silk_Inlines.h defines inline signal processing functions. + */ + +#ifndef _SKP_SILK_FIX_INLINES_H_ +#define _SKP_SILK_FIX_INLINES_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of SKP_int64 */ +SKP_INLINE SKP_int32 SKP_Silk_CLZ64(SKP_int64 in) +{ + SKP_int32 in_upper; + + in_upper = (SKP_int32)SKP_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + SKP_Silk_CLZ32( (SKP_int32) in ); + } else { + /* Search in the upper 32 bits */ + return SKP_Silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +SKP_INLINE void SKP_Silk_CLZ_FRAC(SKP_int32 in, /* I: input */ + SKP_int32 *lz, /* O: number of leading zeros */ + SKP_int32 *frac_Q7) /* O: the 7 bits right after the leading one */ +{ + SKP_int32 lzeros = SKP_Silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = SKP_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +SKP_INLINE SKP_int32 SKP_Silk_SQRT_APPROX(SKP_int32 x) +{ + SKP_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + SKP_Silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= SKP_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = SKP_SMLAWB(y, y, SKP_SMULBB(213, frac_Q7)); + + return y; +} + +/* returns the number of left shifts before overflow for a 16 bit number (ITU definition with norm(0)=0) */ +SKP_INLINE SKP_int32 SKP_Silk_norm16(SKP_int16 a) { + + SKP_int32 a32; + + /* if ((a == 0) || (a == SKP_int16_MIN)) return(0); */ + if ((a << 1) == 0) return(0); + + a32 = a; + /* if (a32 < 0) a32 = -a32 - 1; */ + a32 ^= SKP_RSHIFT(a32, 31); + + return SKP_Silk_CLZ32(a32) - 17; +} + +/* returns the number of left shifts before overflow for a 32 bit number (ITU definition with norm(0)=0) */ +SKP_INLINE SKP_int32 SKP_Silk_norm32(SKP_int32 a) { + + /* if ((a == 0) || (a == SKP_int32_MIN)) return(0); */ + if ((a << 1) == 0) return(0); + + /* if (a < 0) a = -a - 1; */ + a ^= SKP_RSHIFT(a, 31); + + return SKP_Silk_CLZ32(a) - 1; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +SKP_INLINE SKP_int32 SKP_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const SKP_int32 a32, /* I numerator (Q0) */ + const SKP_int32 b32, /* I denominator (Q0) */ + const SKP_int Qres /* I Q-domain of result (>= 0) */ +) +{ + SKP_int a_headrm, b_headrm, lshift; + SKP_int32 b32_inv, a32_nrm, b32_nrm, result; + + SKP_assert( b32 != 0 ); + SKP_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = SKP_Silk_CLZ32( SKP_abs(a32) ) - 1; + a32_nrm = SKP_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = SKP_Silk_CLZ32( SKP_abs(b32) ) - 1; + b32_nrm = SKP_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = SKP_DIV32_16( SKP_int32_MAX >> 2, SKP_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = SKP_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + a32_nrm -= SKP_LSHIFT_ovflw( SKP_SMMUL(b32_nrm, result), 3 ); /* Q: a_headrm */ + + /* Refinement */ + result = SKP_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift <= 0 ) { + return SKP_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return SKP_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +SKP_INLINE SKP_int32 SKP_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const SKP_int32 b32, /* I denominator (Q0) */ + const SKP_int Qres /* I Q-domain of result (> 0) */ +) +{ + SKP_int b_headrm, lshift; + SKP_int32 b32_inv, b32_nrm, err_Q32, result; + + SKP_assert( b32 != 0 ); + SKP_assert( b32 != SKP_int32_MIN ); /* SKP_int32_MIN is not handled by SKP_abs */ + SKP_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = SKP_Silk_CLZ32( SKP_abs(b32) ) - 1; + b32_nrm = SKP_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = SKP_DIV32_16( SKP_int32_MAX >> 2, SKP_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = SKP_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = SKP_LSHIFT_ovflw( -SKP_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = SKP_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return SKP_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return SKP_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#define SKP_SIN_APPROX_CONST0 (1073735400) +#define SKP_SIN_APPROX_CONST1 (-82778932) +#define SKP_SIN_APPROX_CONST2 (1059577) +#define SKP_SIN_APPROX_CONST3 (-5013) + +/* Sine approximation; an input of 65536 corresponds to 2 * pi */ +/* Uses polynomial expansion of the input to the power 0, 2, 4 and 6 */ +/* The relative error is below 1e-5 */ +SKP_INLINE SKP_int32 SKP_Silk_SIN_APPROX_Q24( /* O returns approximately 2^24 * sin(x * 2 * pi / 65536) */ + SKP_int32 x +) +{ + SKP_int y_Q30; + + /* Keep only bottom 16 bits (the function repeats itself with period 65536) */ + x &= 65535; + + /* Split range in four quadrants */ + if( x <= 32768 ) { + if( x < 16384 ) { + /* Return cos(pi/2 - x) */ + x = 16384 - x; + } else { + /* Return cos(x - pi/2) */ + x -= 16384; + } + if( x < 1100 ) { + /* Special case: high accuracy */ + return SKP_SMLAWB( 1 << 24, SKP_MUL( x, x ), -5053 ); + } + x = SKP_SMULWB( SKP_LSHIFT( x, 8 ), x ); /* contains x^2 in Q20 */ + y_Q30 = SKP_SMLAWB( SKP_SIN_APPROX_CONST2, x, SKP_SIN_APPROX_CONST3 ); + y_Q30 = SKP_SMLAWW( SKP_SIN_APPROX_CONST1, x, y_Q30 ); + y_Q30 = SKP_SMLAWW( SKP_SIN_APPROX_CONST0 + 66, x, y_Q30 ); + } else { + if( x < 49152 ) { + /* Return -cos(3*pi/2 - x) */ + x = 49152 - x; + } else { + /* Return -cos(x - 3*pi/2) */ + x -= 49152; + } + if( x < 1100 ) { + /* Special case: high accuracy */ + return SKP_SMLAWB( -(1 << 24), SKP_MUL( x, x ), 5053 ); + } + x = SKP_SMULWB( SKP_LSHIFT( x, 8 ), x ); /* contains x^2 in Q20 */ + y_Q30 = SKP_SMLAWB( -SKP_SIN_APPROX_CONST2, x, -SKP_SIN_APPROX_CONST3 ); + y_Q30 = SKP_SMLAWW( -SKP_SIN_APPROX_CONST1, x, y_Q30 ); + y_Q30 = SKP_SMLAWW( -SKP_SIN_APPROX_CONST0, x, y_Q30 ); + } + return SKP_RSHIFT_ROUND( y_Q30, 6 ); +} + +/* Cosine approximation; an input of 65536 corresponds to 2 * pi */ +/* The relative error is below 1e-5 */ +SKP_INLINE SKP_int32 SKP_Silk_COS_APPROX_Q24( /* O returns approximately 2^24 * cos(x * 2 * pi / 65536) */ + SKP_int32 x +) +{ + return SKP_Silk_SIN_APPROX_Q24( x + 16384 ); +} + +#ifdef __cplusplus +} +#endif + +#endif /*_SKP_SILK_FIX_INLINES_H_*/ diff --git a/pkg/silk/csilk/SKP_Silk_LBRR_reset.c b/pkg/silk/csilk/SKP_Silk_LBRR_reset.c new file mode 100644 index 0000000..f9ef0e6 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LBRR_reset.c @@ -0,0 +1,40 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Resets LBRR buffer, used if packet size changes */ +void SKP_Silk_LBRR_reset( + SKP_Silk_encoder_state *psEncC /* I/O state */ +) +{ + SKP_int i; + + for( i = 0; i < MAX_LBRR_DELAY; i++ ) { + psEncC->LBRR_buffer[ i ].usage = SKP_SILK_NO_LBRR; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c b/pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c new file mode 100644 index 0000000..3f8de6f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_inverse_pred_gain.c * + * * + * Compute inverse of LPC prediction gain, and * + * test if LPC coefficients are stable (all poles within unit circle) * + * * + * Copyright 2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +#undef QA +#define QA 16 +#define A_LIMIT SKP_FIX_CONST( 0.99975, QA ) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static SKP_int LPC_inverse_pred_gain_QA( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + SKP_int32 A_QA[ 2 ][ SKP_Silk_MAX_ORDER_LPC ], + /* I: Prediction coefficients */ + const SKP_int order /* I: Prediction order */ +) +{ + SKP_int k, n, headrm; + SKP_int32 rc_Q31, rc_mult1_Q30, rc_mult2_Q16, tmp_QA; + SKP_int32 *Aold_QA, *Anew_QA; + + Anew_QA = A_QA[ order & 1 ]; + + *invGain_Q30 = ( 1 << 30 ); + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) { + return 1; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -SKP_LSHIFT( Anew_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30-1 ] */ + rc_mult1_Q30 = ( SKP_int32_MAX >> 1 ) - SKP_SMMUL( rc_Q31, rc_Q31 ); + SKP_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + SKP_assert( rc_mult1_Q30 < ( 1 << 30 ) ); + + /* rc_mult2_Q16 range: [ 2^16 : SKP_int32_MAX ] */ + rc_mult2_Q16 = SKP_INVERSE32_varQ( rc_mult1_Q30, 46 ); /* 16 = 46 - 30 */ + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + *invGain_Q30 = SKP_LSHIFT( SKP_SMMUL( *invGain_Q30, rc_mult1_Q30 ), 2 ); + SKP_assert( *invGain_Q30 >= 0 ); + SKP_assert( *invGain_Q30 <= ( 1 << 30 ) ); + + /* Swap pointers */ + Aold_QA = Anew_QA; + Anew_QA = A_QA[ k & 1 ]; + + /* Update AR coefficient */ + headrm = SKP_Silk_CLZ32( rc_mult2_Q16 ) - 1; + rc_mult2_Q16 = SKP_LSHIFT( rc_mult2_Q16, headrm ); /* Q: 16 + headrm */ + for( n = 0; n < k; n++ ) { + tmp_QA = Aold_QA[ n ] - SKP_LSHIFT( SKP_SMMUL( Aold_QA[ k - n - 1 ], rc_Q31 ), 1 ); + Anew_QA[ n ] = SKP_LSHIFT( SKP_SMMUL( tmp_QA, rc_mult2_Q16 ), 16 - headrm ); + } + } + + /* Check for stability */ + if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) { + return 1; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -SKP_LSHIFT( Anew_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = ( SKP_int32_MAX >> 1 ) - SKP_SMMUL( rc_Q31, rc_Q31 ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + *invGain_Q30 = SKP_LSHIFT( SKP_SMMUL( *invGain_Q30, rc_mult1_Q30 ), 2 ); + SKP_assert( *invGain_Q30 >= 0 ); + SKP_assert( *invGain_Q30 <= 1<<30 ); + + return 0; +} +/* For input in Q12 domain */ +SKP_int SKP_Silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int16 *A_Q12, /* I: Prediction coefficients, Q12 [order] */ + const SKP_int order /* I: Prediction order */ +) +{ + SKP_int k; + SKP_int32 Atmp_QA[ 2 ][ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 *Anew_QA; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + Anew_QA[ k ] = SKP_LSHIFT( (SKP_int32)A_Q12[ k ], QA - 12 ); + } + + return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order ); +} + +/* For input in Q24 domain */ +SKP_int SKP_Silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int32 *A_Q24, /* I: Prediction coefficients, Q24 [order] */ + const SKP_int order /* I: Prediction order */ +) +{ + SKP_int k; + SKP_int32 Atmp_QA[ 2 ][ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 *Anew_QA; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + Anew_QA[ k ] = SKP_RSHIFT_ROUND( A_Q24[ k ], 24 - QA ); + } + + return LPC_inverse_pred_gain_QA( invGain_Q30, Atmp_QA, order ); +} + diff --git a/pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c new file mode 100644 index 0000000..9121e58 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_synthesis_filter.c * + * Coefficients are in Q12 * + * * + * even order AR filter * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* even order AR filter */ +void SKP_Silk_LPC_synthesis_filter( + const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [Order], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [Order] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len, /* I: signal length */ + const SKP_int Order /* I: filter order, must be even */ +) +{ + SKP_int k, j, idx, Order_half = SKP_RSHIFT( Order, 1 ); + SKP_int32 SA, SB, out32_Q10, out32; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp, A_align_Q12[ SKP_Silk_MAX_ORDER_LPC >> 1 ]; + + /* combine two A_Q12 values and ensure 32-bit alignment */ + for( k = 0; k < Order_half; k++ ) { + idx = SKP_SMULBB( 2, k ); + A_align_Q12[ k ] = ( ( ( SKP_int32 )A_Q12[ idx ] ) & 0x0000ffff ) | SKP_LSHIFT( ( SKP_int32 )A_Q12[ idx + 1 ], 16 ); + } +#endif + + /* Order must be even */ + SKP_assert( 2 * Order_half == Order ); + + /* S[] values are in Q14 */ + for( k = 0; k < len; k++ ) { + SA = S[ Order - 1 ]; + out32_Q10 = 0; + for( j = 0; j < ( Order_half - 1 ); j++ ) { + idx = SKP_SMULBB( 2, j ) + 1; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* multiply-add two prediction coefficients for each loop */ + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + Atmp = A_align_Q12[ j ]; + SB = S[ Order - 1 - idx ]; + S[ Order - 1 - idx ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT( out32_Q10, SB, Atmp ); + SA = S[ Order - 2 - idx ]; + S[ Order - 2 - idx ] = SB; +#else + SB = S[ Order - 1 - idx ]; + S[ Order - 1 - idx ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, A_Q12[ ( j << 1 ) ] ); + out32_Q10 = SKP_SMLAWB( out32_Q10, SB, A_Q12[ ( j << 1 ) + 1 ] ); + SA = S[ Order - 2 - idx ]; + S[ Order - 2 - idx ] = SB; +#endif + } + +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* unrolled loop: epilog */ + Atmp = A_align_Q12[ Order_half - 1 ]; + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT( out32_Q10, SB, Atmp ); +#else + /* unrolled loop: epilog */ + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, A_Q12[ Order - 2 ] ); + out32_Q10 = SKP_SMLAWB( out32_Q10, SB, A_Q12[ Order - 1 ] ); +#endif + /* apply gain to excitation signal and add to prediction */ + out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) ); + + /* scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 ); + + /* saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* move result into delay line */ + S[ Order - 1 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c new file mode 100644 index 0000000..eae2435 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c @@ -0,0 +1,216 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_LPC_synthesis_order16.c * + * Coefficients are in Q12 * + * * + * 16th order AR filter * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* 16th order AR filter */ +void SKP_Silk_LPC_synthesis_order16(const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [16], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [16] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length, must be multiple of 16 */ +) +{ + SKP_int k; + SKP_int32 SA, SB, out32_Q10, out32; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp, A_align_Q12[ 8 ]; + /* combine two A_Q12 values and ensure 32-bit alignment */ + for( k = 0; k < 8; k++ ) { + A_align_Q12[ k ] = ( ( ( SKP_int32 )A_Q12[ 2 * k ] ) & 0x0000ffff ) | SKP_LSHIFT( ( SKP_int32 )A_Q12[ 2 * k + 1 ], 16 ); + } + /* S[] values are in Q14 */ + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + for( k = 0; k < len; k++ ) { + /* unrolled loop: prolog */ + /* multiply-add two prediction coefficients per iteration */ + SA = S[ 15 ]; + Atmp = A_align_Q12[ 0 ]; + SB = S[ 14 ]; + S[ 14 ] = SA; + out32_Q10 = SKP_SMULWB( SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 13 ]; + S[ 13 ] = SB; + + /* unrolled loop: main loop */ + Atmp = A_align_Q12[ 1 ]; + SB = S[ 12 ]; + S[ 12 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 11 ]; + S[ 11 ] = SB; + + Atmp = A_align_Q12[ 2 ]; + SB = S[ 10 ]; + S[ 10 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 9 ]; + S[ 9 ] = SB; + + Atmp = A_align_Q12[ 3 ]; + SB = S[ 8 ]; + S[ 8 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 7 ]; + S[ 7 ] = SB; + + Atmp = A_align_Q12[ 4 ]; + SB = S[ 6 ]; + S[ 6 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 5 ]; + S[ 5 ] = SB; + + Atmp = A_align_Q12[ 5 ]; + SB = S[ 4 ]; + S[ 4 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 3 ]; + S[ 3 ] = SB; + + Atmp = A_align_Q12[ 6 ]; + SB = S[ 2 ]; + S[ 2 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 1 ]; + S[ 1 ] = SB; + + /* unrolled loop: epilog */ + Atmp = A_align_Q12[ 7 ]; + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + + /* unrolled loop: end */ + /* apply gain to excitation signal and add to prediction */ + out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) ); + + /* scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 ); + + /* saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* move result into delay line */ + S[ 15 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 ); + } +#else + for( k = 0; k < len; k++ ) { + /* unrolled loop: prolog */ + /* multiply-add two prediction coefficients per iteration */ + SA = S[ 15 ]; + SB = S[ 14 ]; + S[ 14 ] = SA; + out32_Q10 = SKP_SMULWB( SA, A_Q12[ 0 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 1 ] ); + SA = S[ 13 ]; + S[ 13 ] = SB; + + /* unrolled loop: main loop */ + SB = S[ 12 ]; + S[ 12 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 2 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 3 ] ); + SA = S[ 11 ]; + S[ 11 ] = SB; + + SB = S[ 10 ]; + S[ 10 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 4 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 5 ] ); + SA = S[ 9 ]; + S[ 9 ] = SB; + + SB = S[ 8 ]; + S[ 8 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 6 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 7 ] ); + SA = S[ 7 ]; + S[ 7 ] = SB; + + SB = S[ 6 ]; + S[ 6 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 8 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 9 ] ); + SA = S[ 5 ]; + S[ 5 ] = SB; + + SB = S[ 4 ]; + S[ 4 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 10 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 11 ] ); + SA = S[ 3 ]; + S[ 3 ] = SB; + + SB = S[ 2 ]; + S[ 2 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 12 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 13 ] ); + SA = S[ 1 ]; + S[ 1 ] = SB; + + /* unrolled loop: epilog */ + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, A_Q12[ 14 ] ); + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SB, A_Q12[ 15 ] ); + + /* unrolled loop: end */ + /* apply gain to excitation signal and add to prediction */ + out32_Q10 = SKP_ADD_SAT32( out32_Q10, SKP_SMULWB( Gain_Q26, in[ k ] ) ); + + /* scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q10, 10 ); + + /* saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* move result into delay line */ + S[ 15 ] = SKP_LSHIFT_SAT32( out32_Q10, 4 ); + } +#endif +} + + diff --git a/pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c b/pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c new file mode 100644 index 0000000..ed19466 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c @@ -0,0 +1,194 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. + +*/ +#include "SKP_Silk_main.h" + +#if SWITCH_TRANSITION_FILTERING + +/* Helper function, that interpolates the filter taps */ +SKP_INLINE void SKP_Silk_LP_interpolate_filter_taps( + SKP_int32 B_Q28[ TRANSITION_NB ], + SKP_int32 A_Q28[ TRANSITION_NA ], + const SKP_int ind, + const SKP_int32 fac_Q16 +) +{ + SKP_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 == SKP_SAT16( fac_Q16 ) ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ], + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ], + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else if( fac_Q16 == ( 1 << 15 ) ) { /* Neither fac_Q16 nor ( ( 1 << 16 ) - fac_Q16 ) is in range of a 16-bit int */ + + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = SKP_RSHIFT( + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ] + + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + 1 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = SKP_RSHIFT( + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ] + + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + 1 ); + } + } else { /* ( ( 1 << 16 ) - fac_Q16 ) is in range of a 16-bit int */ + + SKP_assert( ( ( 1 << 16 ) - fac_Q16 ) == SKP_SAT16( ( ( 1 << 16 ) - fac_Q16) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + SKP_Silk_Transition_LP_B_Q28[ ind ][ nb ] - + SKP_Silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + ( 1 << 16 ) - fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = SKP_SMLAWB( + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + SKP_Silk_Transition_LP_A_Q28[ ind ][ na ] - + SKP_Silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + ( 1 << 16 ) - fac_Q16 ); + } + } + } else { + SKP_memcpy( B_Q28, SKP_Silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( SKP_int32 ) ); + SKP_memcpy( A_Q28, SKP_Silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( SKP_int32 ) ); + } + } else { + SKP_memcpy( B_Q28, SKP_Silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( SKP_int32 ) ); + SKP_memcpy( A_Q28, SKP_Silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( SKP_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->transition_frame_no = 1; */ +/* Deactivate by setting psEncC->transition_frame_no = 0; */ +void SKP_Silk_LP_variable_cutoff( + SKP_Silk_LP_state *psLP, /* I/O LP filter state */ + SKP_int16 *out, /* O Low-pass filtered output signal */ + const SKP_int16 *in, /* I Input signal */ + const SKP_int frame_length /* I Frame length */ +) +{ + SKP_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + SKP_int ind = 0; + + SKP_assert( psLP->transition_frame_no >= 0 ); + SKP_assert( ( ( ( psLP->transition_frame_no <= TRANSITION_FRAMES_DOWN ) && ( psLP->mode == 0 ) ) || + ( ( psLP->transition_frame_no <= TRANSITION_FRAMES_UP ) && ( psLP->mode == 1 ) ) ) ); + + /* Interpolate filter coefficients if needed */ + if( psLP->transition_frame_no > 0 ) { + if( psLP->mode == 0 ) { + if( psLP->transition_frame_no < TRANSITION_FRAMES_DOWN ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS_DOWN == 32 ) + fac_Q16 = SKP_LSHIFT( psLP->transition_frame_no, 16 - 5 ); +#else + fac_Q16 = SKP_DIV32_16( SKP_LSHIFT( psLP->transition_frame_no, 16 ), TRANSITION_INT_STEPS_DOWN ); +#endif + ind = SKP_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= SKP_LSHIFT( ind, 16 ); + + SKP_assert( ind >= 0 ); + SKP_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Increment transition frame number for next frame */ + psLP->transition_frame_no++; + + } else { + SKP_assert( psLP->transition_frame_no == TRANSITION_FRAMES_DOWN ); + /* End of transition phase */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, TRANSITION_INT_NUM - 1, 0 ); + } + } else { + SKP_assert( psLP->mode == 1 ); + if( psLP->transition_frame_no < TRANSITION_FRAMES_UP ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS_UP == 64 ) + fac_Q16 = SKP_LSHIFT( TRANSITION_FRAMES_UP - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = SKP_DIV32_16( SKP_LSHIFT( TRANSITION_FRAMES_UP - psLP->transition_frame_no, 16 ), TRANSITION_INT_STEPS_UP ); +#endif + ind = SKP_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= SKP_LSHIFT( ind, 16 ); + + SKP_assert( ind >= 0 ); + SKP_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Increment transition frame number for next frame */ + psLP->transition_frame_no++; + + } else { + SKP_assert( psLP->transition_frame_no == TRANSITION_FRAMES_UP ); + /* End of transition phase */ + SKP_Silk_LP_interpolate_filter_taps( B_Q28, A_Q28, 0, 0 ); + } + } + } + + if( psLP->transition_frame_no > 0 ) { + /* ARMA low-pass filtering */ + SKP_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + SKP_Silk_biquad_alt( in, B_Q28, A_Q28, psLP->In_LP_State, out, frame_length ); + } else { + /* Instead of using the filter, copy input directly to output */ + SKP_memcpy( out, in, frame_length * sizeof( SKP_int16 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_LSF_cos_table.c b/pkg/silk/csilk/SKP_Silk_LSF_cos_table.c new file mode 100644 index 0000000..4d9ffe5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LSF_cos_table.c @@ -0,0 +1,65 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +// Q12 values (even) +const SKP_int SKP_Silk_LSFCosTab_FIX_Q12[LSF_COS_TAB_SZ_FIX + 1] = { + 8192, 8190, 8182, 8170, + 8152, 8130, 8104, 8072, + 8034, 7994, 7946, 7896, + 7840, 7778, 7714, 7644, + 7568, 7490, 7406, 7318, + 7226, 7128, 7026, 6922, + 6812, 6698, 6580, 6458, + 6332, 6204, 6070, 5934, + 5792, 5648, 5502, 5352, + 5198, 5040, 4880, 4718, + 4552, 4382, 4212, 4038, + 3862, 3684, 3502, 3320, + 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, + 1598, 1400, 1202, 1002, + 802, 602, 402, 202, + 0, -202, -402, -602, + -802, -1002, -1202, -1400, + -1598, -1794, -1990, -2186, + -2378, -2570, -2760, -2948, + -3136, -3320, -3502, -3684, + -3862, -4038, -4212, -4382, + -4552, -4718, -4880, -5040, + -5198, -5352, -5502, -5648, + -5792, -5934, -6070, -6204, + -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, + -7226, -7318, -7406, -7490, + -7568, -7644, -7714, -7778, + -7840, -7896, -7946, -7994, + -8034, -8072, -8104, -8130, + -8152, -8170, -8182, -8190, + -8192 +}; diff --git a/pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.c b/pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.c new file mode 100644 index 0000000..612124c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +void SKP_Silk_LTP_analysis_filter_FIX( + SKP_int16 *LTP_res, /* O: LTP residual signal of length NB_SUBFR * ( pre_length + subfr_length ) */ + const SKP_int16 *x, /* I: Pointer to input signal with at least max( pitchL ) preceeding samples */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ],/* I: LTP_ORDER LTP coefficients for each NB_SUBFR subframe */ + const SKP_int pitchL[ NB_SUBFR ], /* I: Pitch lag, one for each subframe */ + const SKP_int32 invGains_Q16[ NB_SUBFR ], /* I: Inverse quantization gains, one for each subframe */ + const SKP_int subfr_length, /* I: Length of each subframe */ + const SKP_int pre_length /* I: Length of the preceeding samples starting at &x[0] for each subframe */ +) +{ + const SKP_int16 *x_ptr, *x_lag_ptr; + SKP_int16 Btmp_Q14[ LTP_ORDER ]; + SKP_int16 *LTP_res_ptr; + SKP_int k, i, j; + SKP_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 ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp_Q14[ i ] = LTPCoef_Q14[ k * LTP_ORDER + i ]; + } + + /* 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 = SKP_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + for( j = 1; j < LTP_ORDER; j++ ) { + LTP_est = SKP_SMLABB_ovflw( LTP_est, x_lag_ptr[ LTP_ORDER / 2 - j ], Btmp_Q14[ j ] ); + } + LTP_est = SKP_RSHIFT_ROUND( LTP_est, 14 ); // round and -> Q0 + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = ( SKP_int16 )SKP_SAT16( ( SKP_int32 )x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = SKP_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c b/pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c new file mode 100644 index 0000000..51283b5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +#define NB_THRESHOLDS 11 + +/* Table containing trained thresholds for LTP scaling */ +static const SKP_int16 LTPScaleThresholds_Q15[ NB_THRESHOLDS ] = +{ + 31129, 26214, 16384, 13107, 9830, 6554, + 4915, 3276, 2621, 2458, 0 +}; + +void SKP_Silk_LTP_scale_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O encoder control FIX */ +) +{ + SKP_int round_loss, frames_per_packet; + SKP_int g_out_Q5, g_limit_Q15, thrld1_Q15, thrld2_Q15; + + /* 1st order high-pass filter */ + psEnc->HPLTPredCodGain_Q7 = SKP_max_int( psEncCtrl->LTPredCodGain_Q7 - psEnc->prevLTPredCodGain_Q7, 0 ) + + SKP_RSHIFT_ROUND( psEnc->HPLTPredCodGain_Q7, 1 ); + + psEnc->prevLTPredCodGain_Q7 = psEncCtrl->LTPredCodGain_Q7; + + /* combine input and filtered input */ + g_out_Q5 = SKP_RSHIFT_ROUND( SKP_RSHIFT( psEncCtrl->LTPredCodGain_Q7, 1 ) + SKP_RSHIFT( psEnc->HPLTPredCodGain_Q7, 1 ), 3 ); + g_limit_Q15 = SKP_Silk_sigm_Q15( g_out_Q5 - ( 3 << 5 ) ); + + /* Default is minimum scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 0; + + /* Round the loss measure to whole pct */ + round_loss = ( SKP_int )psEnc->sCmn.PacketLoss_perc; + + /* Only scale if first frame in packet 0% */ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + + frames_per_packet = SKP_DIV32_16( psEnc->sCmn.PacketSize_ms, FRAME_LENGTH_MS ); + + round_loss += frames_per_packet - 1; + thrld1_Q15 = LTPScaleThresholds_Q15[ SKP_min_int( round_loss, NB_THRESHOLDS - 1 ) ]; + thrld2_Q15 = LTPScaleThresholds_Q15[ SKP_min_int( round_loss + 1, NB_THRESHOLDS - 1 ) ]; + + if( g_limit_Q15 > thrld1_Q15 ) { + /* Maximum scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 2; + } else if( g_limit_Q15 > thrld2_Q15 ) { + /* Medium scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 1; + } + } + psEncCtrl->LTP_scale_Q14 = SKP_Silk_LTPScales_table_Q14[ psEncCtrl->sCmn.LTP_scaleIndex ]; +} diff --git a/pkg/silk/csilk/SKP_Silk_MA.c b/pkg/silk/csilk/SKP_Silk_MA.c new file mode 100644 index 0000000..fcdce14 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_MA.c @@ -0,0 +1,120 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_MA.c * + * * + * Variable order MA filter * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +#if EMBEDDED_ARM<5 +/* Variable order MA prediction error filter */ +void SKP_Silk_MA_Prediction( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int32 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 order /* I: Filter order */ +) +{ + SKP_int k, d, in16; + SKP_int32 out32; + + for( k = 0; k < len; k++ ) { + in16 = in[ k ]; + out32 = SKP_LSHIFT( in16, 12 ) - S[ 0 ]; + out32 = SKP_RSHIFT_ROUND( out32, 12 ); + + for( d = 0; d < order - 1; d++ ) { + S[ d ] = SKP_SMLABB_ovflw( S[ d + 1 ], in16, B[ d ] ); + } + S[ order - 1 ] = SKP_SMULBB( in16, B[ order - 1 ] ); + + /* Limit */ + out[ k ] = (SKP_int16)SKP_SAT16( out32 ); + } +} +#endif + +#if EMBEDDED_ARM<5 + +void SKP_Silk_LPC_analysis_filter( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int16 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 Order /* I: Filter order */ +) +{ + SKP_int k, j, idx, Order_half = SKP_RSHIFT( Order, 1 ); + SKP_int32 out32_Q12, out32; + SKP_int16 SA, SB; + /* Order must be even */ + SKP_assert( 2 * Order_half == Order ); + + /* S[] values are in Q0 */ + for( k = 0; k < len; k++ ) { + SA = S[ 0 ]; + out32_Q12 = 0; + for( j = 0; j < ( Order_half - 1 ); j++ ) { + idx = SKP_SMULBB( 2, j ) + 1; + /* Multiply-add two prediction coefficients for each loop */ + SB = S[ idx ]; + S[ idx ] = SA; + out32_Q12 = SKP_SMLABB( out32_Q12, SA, B[ idx - 1 ] ); + out32_Q12 = SKP_SMLABB( out32_Q12, SB, B[ idx ] ); + SA = S[ idx + 1 ]; + S[ idx + 1 ] = SB; + } + + /* Unrolled loop: epilog */ + SB = S[ Order - 1 ]; + S[ Order - 1 ] = SA; + out32_Q12 = SKP_SMLABB( out32_Q12, SA, B[ Order - 2 ] ); + out32_Q12 = SKP_SMLABB( out32_Q12, SB, B[ Order - 1 ] ); + + /* Subtract prediction */ + out32_Q12 = SKP_SUB_SAT32( SKP_LSHIFT( (SKP_int32)in[ k ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = SKP_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ k ] = ( SKP_int16 )SKP_SAT16( out32 ); + + /* Move input line */ + S[ 0 ] = in[ k ]; + } +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_NLSF2A.c b/pkg/silk/csilk/SKP_Silk_NLSF2A.c new file mode 100644 index 0000000..732b0f9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF2A.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* function are accurate inverses of each other */ + +#include "SKP_Silk_SigProc_FIX.h" + +/* helper function for NLSF2A(..) */ +SKP_INLINE void SKP_Silk_NLSF2A_find_poly( + SKP_int32 *out, /* o intermediate polynomial, Q20 */ + const SKP_int32 *cLSF, /* i vector of interleaved 2*cos(LSFs), Q20 */ + SKP_int dd /* i polynomial order (= 1/2 * filter order) */ +) +{ + SKP_int k, n; + SKP_int32 ftmp; + + out[0] = SKP_LSHIFT( 1, 20 ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; // Q20 + out[k+1] = SKP_LSHIFT( out[k-1], 1 ) - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[k] ), 20 ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (SKP_int32)SKP_RSHIFT_ROUND64( SKP_SMULL( ftmp, out[n-1] ), 20 ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void SKP_Silk_NLSF2A( + SKP_int16 *a, /* o monic whitening filter coefficients in Q12, [d] */ + const SKP_int *NLSF, /* i normalized line spectral frequencies in Q15, [d] */ + const SKP_int d /* i filter order (should be even) */ +) +{ + SKP_int k, i, dd; + SKP_int32 cos_LSF_Q20[SKP_Silk_MAX_ORDER_LPC]; + SKP_int32 P[SKP_Silk_MAX_ORDER_LPC/2+1], Q[SKP_Silk_MAX_ORDER_LPC/2+1]; + SKP_int32 Ptmp, Qtmp; + SKP_int32 f_int; + SKP_int32 f_frac; + SKP_int32 cos_val, delta; + SKP_int32 a_int32[SKP_Silk_MAX_ORDER_LPC]; + SKP_int32 maxabs, absval, idx=0, sc_Q16; + + SKP_assert(LSF_COS_TAB_SZ_FIX == 128); + + /* convert LSFs to 2*cos(LSF(i)), using piecewise linear curve from table */ + for( k = 0; k < d; k++ ) { + SKP_assert(NLSF[k] >= 0 ); + SKP_assert(NLSF[k] <= 32767 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = SKP_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - SKP_LSHIFT( f_int, 15 - 7 ); + + SKP_assert(f_int >= 0); + SKP_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = SKP_Silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = SKP_Silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_Q20[k] = SKP_LSHIFT( cos_val, 8 ) + SKP_MUL( delta, f_frac ); /* Q20 */ + } + + dd = SKP_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + SKP_Silk_NLSF2A_find_poly( P, &cos_LSF_Q20[0], dd ); + SKP_Silk_NLSF2A_find_poly( Q, &cos_LSF_Q20[1], dd ); + + /* convert even and odd polynomials to SKP_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[k+1] + P[k]; + Qtmp = Q[k+1] - Q[k]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + + a_int32[k] = -SKP_RSHIFT_ROUND( Ptmp + Qtmp, 9 ); /* Q20 -> Q12 */ + a_int32[d-k-1] = SKP_RSHIFT_ROUND( Qtmp - Ptmp, 9 ); /* Q20 -> Q12 */ + } + + /* Limit the maximum absolute value of the prediction coefficients */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = SKP_abs( a_int32[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + + if( maxabs > SKP_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = SKP_min( maxabs, 98369 ); // ( SKP_int32_MAX / ( 65470 >> 2 ) ) + SKP_int16_MAX = 98369 + sc_Q16 = 65470 - SKP_DIV32( SKP_MUL( 65470 >> 2, maxabs - SKP_int16_MAX ), + SKP_RSHIFT32( SKP_MUL( maxabs, idx + 1), 2 ) ); + SKP_Silk_bwexpander_32( a_int32, d, sc_Q16 ); + } else { + break; + } + } + + /* Reached the last iteration */ + if( i == 10 ) { + SKP_assert(0); + for( k = 0; k < d; k++ ) { + a_int32[k] = SKP_SAT16( a_int32[k] ); + } + } + + /* Return as SKP_int16 Q12 coefficients */ + for( k = 0; k < d; k++ ) { + a[k] = (SKP_int16)a_int32[k]; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c b/pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c new file mode 100644 index 0000000..63da339 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Convert NLSF parameters to stable AR prediction filter coefficients */ +void SKP_Silk_NLSF2A_stable( + SKP_int16 pAR_Q12[ MAX_LPC_ORDER ], /* O Stabilized AR coefs [LPC_order] */ + const SKP_int pNLSF[ MAX_LPC_ORDER ], /* I NLSF vector [LPC_order] */ + const SKP_int LPC_order /* I LPC/LSF order */ +) +{ + SKP_int i; + SKP_int32 invGain_Q30; + + SKP_Silk_NLSF2A( pAR_Q12, pNLSF, LPC_order ); + + /* Ensure stable LPCs */ + for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + if( SKP_Silk_LPC_inverse_pred_gain( &invGain_Q30, pAR_Q12, LPC_order ) == 1 ) { + SKP_Silk_bwexpander( pAR_Q12, LPC_order, 65536 - SKP_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015 */ + } else { + break; + } + } + + /* Reached the last iteration */ + if( i == MAX_LPC_STABILIZE_ITERATIONS ) { + SKP_assert( 0 ); + for( i = 0; i < LPC_order; i++ ) { + pAR_Q12[ i ] = 0; + } + } +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c new file mode 100644 index 0000000..aa3983f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* NLSF vector decoder */ +void SKP_Silk_NLSF_MSVQ_decode( + SKP_int *pNLSF_Q15, /* O Pointer to decoded output vector [LPC_ORDER x 1] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Pointer to NLSF codebook struct */ + const SKP_int *NLSFIndices, /* I Pointer to NLSF indices [nStages x 1] */ + const SKP_int LPC_order /* I LPC order used */ +) +{ + const SKP_int16 *pCB_element; + SKP_int s; + SKP_int i; + + /* Check that each index is within valid range */ + SKP_assert( 0 <= NLSFIndices[ 0 ] && NLSFIndices[ 0 ] < psNLSF_CB->CBStages[ 0 ].nVectors ); + + /* Point to the first vector element */ + pCB_element = &psNLSF_CB->CBStages[ 0 ].CB_NLSF_Q15[ SKP_MUL( NLSFIndices[ 0 ], LPC_order ) ]; + + /* Initialize with the codebook vector from stage 0 */ + for( i = 0; i < LPC_order; i++ ) { + pNLSF_Q15[ i ] = ( SKP_int )pCB_element[ i ]; + } + + for( s = 1; s < psNLSF_CB->nStages; s++ ) { + /* Check that each index is within valid range */ + SKP_assert( 0 <= NLSFIndices[ s ] && NLSFIndices[ s ] < psNLSF_CB->CBStages[ s ].nVectors ); + + if( LPC_order == 16 ) { + /* Point to the first vector element */ + pCB_element = &psNLSF_CB->CBStages[ s ].CB_NLSF_Q15[ SKP_LSHIFT( NLSFIndices[ s ], 4 ) ]; + + /* Add the codebook vector from the current stage */ + pNLSF_Q15[ 0 ] += pCB_element[ 0 ]; + pNLSF_Q15[ 1 ] += pCB_element[ 1 ]; + pNLSF_Q15[ 2 ] += pCB_element[ 2 ]; + pNLSF_Q15[ 3 ] += pCB_element[ 3 ]; + pNLSF_Q15[ 4 ] += pCB_element[ 4 ]; + pNLSF_Q15[ 5 ] += pCB_element[ 5 ]; + pNLSF_Q15[ 6 ] += pCB_element[ 6 ]; + pNLSF_Q15[ 7 ] += pCB_element[ 7 ]; + pNLSF_Q15[ 8 ] += pCB_element[ 8 ]; + pNLSF_Q15[ 9 ] += pCB_element[ 9 ]; + pNLSF_Q15[ 10 ] += pCB_element[ 10 ]; + pNLSF_Q15[ 11 ] += pCB_element[ 11 ]; + pNLSF_Q15[ 12 ] += pCB_element[ 12 ]; + pNLSF_Q15[ 13 ] += pCB_element[ 13 ]; + pNLSF_Q15[ 14 ] += pCB_element[ 14 ]; + pNLSF_Q15[ 15 ] += pCB_element[ 15 ]; + } else { + /* Point to the first vector element */ + pCB_element = &psNLSF_CB->CBStages[ s ].CB_NLSF_Q15[ SKP_SMULBB( NLSFIndices[ s ], LPC_order ) ]; + + /* Add the codebook vector from the current stage */ + for( i = 0; i < LPC_order; i++ ) { + pNLSF_Q15[ i ] += pCB_element[ i ]; + } + } + } + + /* NLSF stabilization */ + SKP_Silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->NDeltaMin_Q15, LPC_order ); +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c new file mode 100644 index 0000000..5bae4de --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c @@ -0,0 +1,239 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +void SKP_Silk_NLSF_MSVQ_encode_FIX( + SKP_int *NLSFIndices, /* O Codebook path vector [ CB_STAGES ] */ + SKP_int *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const SKP_int *pNLSF_q_Q15_prev, /* I Prev. quantized NLSF vector [LPC_ORDER] */ + const SKP_int *pW_Q6, /* I NLSF weight vector [ LPC_ORDER ] */ + const SKP_int NLSF_mu_Q15, /* I Rate weight for the RD optimization */ + const SKP_int NLSF_mu_fluc_red_Q16, /* I Fluctuation reduction error weight */ + const SKP_int NLSF_MSVQ_Survivors, /* I Max survivors from each stage */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int deactivate_fluc_red /* I Deactivate fluctuation reduction */ +) +{ + SKP_int i, s, k, cur_survivors = 0, prev_survivors, min_survivors, input_index, cb_index, bestIndex; + SKP_int32 rateDistThreshold_Q18; +#if( NLSF_MSVQ_FLUCTUATION_REDUCTION == 1 ) + SKP_int32 se_Q15, wsse_Q20, bestRateDist_Q20; +#endif + +#if( LOW_COMPLEXITY_ONLY == 1 ) + SKP_int32 pRateDist_Q18[ NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE ]; + SKP_int32 pRate_Q5[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_int32 pRate_new_Q5[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_int pTempIndices[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_int pPath[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pPath_new[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pRes_Q15[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * MAX_LPC_ORDER ]; + SKP_int pRes_new_Q15[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * MAX_LPC_ORDER ]; +#else + SKP_int32 pRateDist_Q18[ NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED ]; + SKP_int32 pRate_Q5[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_int32 pRate_new_Q5[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_int pTempIndices[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_int pPath[ MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pPath_new[ MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pRes_Q15[ MAX_NLSF_MSVQ_SURVIVORS * MAX_LPC_ORDER ]; + SKP_int pRes_new_Q15[ MAX_NLSF_MSVQ_SURVIVORS * MAX_LPC_ORDER ]; +#endif + + const SKP_int *pConstInt; + SKP_int *pInt; + const SKP_int16 *pCB_element; + const SKP_Silk_NLSF_CBS *pCurrentCBStage; + +#ifdef USE_UNQUANTIZED_LSFS + SKP_int NLSF_orig[ MAX_LPC_ORDER ]; + SKP_memcpy( NLSF_orig, pNLSF_Q15, LPC_order * sizeof( SKP_int ) ); +#endif + + SKP_assert( NLSF_MSVQ_Survivors <= MAX_NLSF_MSVQ_SURVIVORS ); + SKP_assert( ( LOW_COMPLEXITY_ONLY == 0 ) || ( NLSF_MSVQ_Survivors <= MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ) ); + + + /****************************************************/ + /* Tree search for the multi-stage vector quantizer */ + /****************************************************/ + + /* Clear accumulated rates */ + SKP_memset( pRate_Q5, 0, NLSF_MSVQ_Survivors * sizeof( SKP_int32 ) ); + + /* Copy NLSFs into residual signal vector */ + for( i = 0; i < LPC_order; i++ ) { + pRes_Q15[ i ] = pNLSF_Q15[ i ]; + } + + /* Set first stage values */ + prev_survivors = 1; + + /* Minimum number of survivors */ + min_survivors = NLSF_MSVQ_Survivors / 2; + + /* Loop over all stages */ + for( s = 0; s < psNLSF_CB->nStages; s++ ) { + + /* Set a pointer to the current stage codebook */ + pCurrentCBStage = &psNLSF_CB->CBStages[ s ]; + + /* Calculate the number of survivors in the current stage */ + cur_survivors = SKP_min_32( NLSF_MSVQ_Survivors, SKP_SMULBB( prev_survivors, pCurrentCBStage->nVectors ) ); + +#if( NLSF_MSVQ_FLUCTUATION_REDUCTION == 0 ) + /* Find a single best survivor in the last stage, if we */ + /* do not need candidates for fluctuation reduction */ + if( s == psNLSF_CB->nStages - 1 ) { + cur_survivors = 1; + } +#endif + + /* Nearest neighbor clustering for multiple input data vectors */ + SKP_Silk_NLSF_VQ_rate_distortion_FIX( pRateDist_Q18, pCurrentCBStage, pRes_Q15, pW_Q6, + pRate_Q5, NLSF_mu_Q15, prev_survivors, LPC_order ); + + /* Sort the rate-distortion errors */ + SKP_Silk_insertion_sort_increasing( pRateDist_Q18, pTempIndices, + prev_survivors * pCurrentCBStage->nVectors, cur_survivors ); + + /* Discard survivors with rate-distortion values too far above the best one */ + if( pRateDist_Q18[ 0 ] < SKP_int32_MAX / MAX_NLSF_MSVQ_SURVIVORS ) { + rateDistThreshold_Q18 = SKP_SMLAWB( pRateDist_Q18[ 0 ], + SKP_MUL( NLSF_MSVQ_Survivors, pRateDist_Q18[ 0 ] ), SKP_FIX_CONST( NLSF_MSVQ_SURV_MAX_REL_RD, 16 ) ); + while( pRateDist_Q18[ cur_survivors - 1 ] > rateDistThreshold_Q18 && cur_survivors > min_survivors ) { + cur_survivors--; + } + } + /* Update accumulated codebook contributions for the 'cur_survivors' best codebook indices */ + for( k = 0; k < cur_survivors; k++ ) { + if( s > 0 ) { + /* Find the indices of the input and the codebook vector */ + if( pCurrentCBStage->nVectors == 8 ) { + input_index = SKP_RSHIFT( pTempIndices[ k ], 3 ); + cb_index = pTempIndices[ k ] & 7; + } else { + input_index = SKP_DIV32_16( pTempIndices[ k ], pCurrentCBStage->nVectors ); + cb_index = pTempIndices[ k ] - SKP_SMULBB( input_index, pCurrentCBStage->nVectors ); + } + } else { + /* Find the indices of the input and the codebook vector */ + input_index = 0; + cb_index = pTempIndices[ k ]; + } + + /* Subtract new contribution from the previous residual vector for each of 'cur_survivors' */ + pConstInt = &pRes_Q15[ SKP_SMULBB( input_index, LPC_order ) ]; + pCB_element = &pCurrentCBStage->CB_NLSF_Q15[ SKP_SMULBB( cb_index, LPC_order ) ]; + pInt = &pRes_new_Q15[ SKP_SMULBB( k, LPC_order ) ]; + for( i = 0; i < LPC_order; i++ ) { + pInt[ i ] = pConstInt[ i ] - ( SKP_int )pCB_element[ i ]; + } + + /* Update accumulated rate for stage 1 to the current */ + pRate_new_Q5[ k ] = pRate_Q5[ input_index ] + pCurrentCBStage->Rates_Q5[ cb_index ]; + + /* Copy paths from previous matrix, starting with the best path */ + pConstInt = &pPath[ SKP_SMULBB( input_index, psNLSF_CB->nStages ) ]; + pInt = &pPath_new[ SKP_SMULBB( k, psNLSF_CB->nStages ) ]; + for( i = 0; i < s; i++ ) { + pInt[ i ] = pConstInt[ i ]; + } + /* Write the current stage indices for the 'cur_survivors' to the best path matrix */ + pInt[ s ] = cb_index; + } + + if( s < psNLSF_CB->nStages - 1 ) { + /* Copy NLSF residual matrix for next stage */ + SKP_memcpy( pRes_Q15, pRes_new_Q15, SKP_SMULBB( cur_survivors, LPC_order ) * sizeof( SKP_int ) ); + + /* Copy rate vector for next stage */ + SKP_memcpy( pRate_Q5, pRate_new_Q5, cur_survivors * sizeof( SKP_int32 ) ); + + /* Copy best path matrix for next stage */ + SKP_memcpy( pPath, pPath_new, SKP_SMULBB( cur_survivors, psNLSF_CB->nStages ) * sizeof( SKP_int ) ); + } + + prev_survivors = cur_survivors; + } + + /* (Preliminary) index of the best survivor, later to be decoded */ + bestIndex = 0; + +#if( NLSF_MSVQ_FLUCTUATION_REDUCTION == 1 ) + /******************************/ + /* NLSF fluctuation reduction */ + /******************************/ + if( deactivate_fluc_red != 1 ) { + + /* Search among all survivors, now taking also weighted fluctuation errors into account */ + bestRateDist_Q20 = SKP_int32_MAX; + for( s = 0; s < cur_survivors; s++ ) { + /* Decode survivor to compare with previous quantized NLSF vector */ + SKP_Silk_NLSF_MSVQ_decode( pNLSF_Q15, psNLSF_CB, &pPath_new[ SKP_SMULBB( s, psNLSF_CB->nStages ) ], LPC_order ); + + /* Compare decoded NLSF vector with the previously quantized vector */ + wsse_Q20 = 0; + for( i = 0; i < LPC_order; i += 2 ) { + /* Compute weighted squared quantization error for index i */ + se_Q15 = pNLSF_Q15[ i ] - pNLSF_q_Q15_prev[ i ]; // range: [ -32767 : 32767 ] + wsse_Q20 = SKP_SMLAWB( wsse_Q20, SKP_SMULBB( se_Q15, se_Q15 ), pW_Q6[ i ] ); + + /* Compute weighted squared quantization error for index i + 1 */ + se_Q15 = pNLSF_Q15[ i + 1 ] - pNLSF_q_Q15_prev[ i + 1 ]; // range: [ -32767 : 32767 ] + wsse_Q20 = SKP_SMLAWB( wsse_Q20, SKP_SMULBB( se_Q15, se_Q15 ), pW_Q6[ i + 1 ] ); + } + SKP_assert( wsse_Q20 >= 0 ); + + /* Add the fluctuation reduction penalty to the rate distortion error */ + wsse_Q20 = SKP_ADD_POS_SAT32( pRateDist_Q18[ s ], SKP_SMULWB( wsse_Q20, NLSF_mu_fluc_red_Q16 ) ); + + /* Keep index of best survivor */ + if( wsse_Q20 < bestRateDist_Q20 ) { + bestRateDist_Q20 = wsse_Q20; + bestIndex = s; + } + } + } +#endif + + /* Copy best path to output argument */ + SKP_memcpy( NLSFIndices, &pPath_new[ SKP_SMULBB( bestIndex, psNLSF_CB->nStages ) ], psNLSF_CB->nStages * sizeof( SKP_int ) ); + + /* Decode and stabilize the best survivor */ + SKP_Silk_NLSF_MSVQ_decode( pNLSF_Q15, psNLSF_CB, NLSFIndices, LPC_order ); + +#ifdef USE_UNQUANTIZED_LSFS + SKP_memcpy( pNLSF_Q15, NLSF_orig, LPC_order * sizeof( SKP_int ) ); +#endif + +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c new file mode 100644 index 0000000..8b5704d --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Rate-Distortion calculations for multiple input data vectors */ +void SKP_Silk_NLSF_VQ_rate_distortion_FIX( + SKP_int32 *pRD_Q20, /* O Rate-distortion values [psNLSF_CBS->nVectors*N] */ + const SKP_Silk_NLSF_CBS *psNLSF_CBS, /* I NLSF codebook stage struct */ + const SKP_int *in_Q15, /* I Input vectors to be quantized */ + const SKP_int *w_Q6, /* I Weight vector */ + const SKP_int32 *rate_acc_Q5, /* I Accumulated rates from previous stage */ + const SKP_int mu_Q15, /* I Weight between weighted error and rate */ + const SKP_int N, /* I Number of input vectors to be quantized */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int i, n; + SKP_int32 *pRD_vec_Q20; + + /* Compute weighted quantization errors for all input vectors over one codebook stage */ + SKP_Silk_NLSF_VQ_sum_error_FIX( pRD_Q20, in_Q15, w_Q6, psNLSF_CBS->CB_NLSF_Q15, + N, psNLSF_CBS->nVectors, LPC_order ); + + /* Loop over input vectors */ + pRD_vec_Q20 = pRD_Q20; + for( n = 0; n < N; n++ ) { + /* Add rate cost to error for each codebook vector */ + for( i = 0; i < psNLSF_CBS->nVectors; i++ ) { + SKP_assert( rate_acc_Q5[ n ] + psNLSF_CBS->Rates_Q5[ i ] >= 0 ); + SKP_assert( rate_acc_Q5[ n ] + psNLSF_CBS->Rates_Q5[ i ] <= SKP_int16_MAX ); + pRD_vec_Q20[ i ] = SKP_SMLABB( pRD_vec_Q20[ i ], rate_acc_Q5[ n ] + psNLSF_CBS->Rates_Q5[ i ], mu_Q15 ); + SKP_assert( pRD_vec_Q20[ i ] >= 0 ); + } + pRD_vec_Q20 += psNLSF_CBS->nVectors; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c new file mode 100644 index 0000000..05d90d0 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +#if (!defined(__mips__)) && (EMBEDDED_ARM < 6) + +/* Compute weighted quantization errors for an LPC_order element input vector, over one codebook stage */ +void SKP_Silk_NLSF_VQ_sum_error_FIX( + SKP_int32 *err_Q20, /* O Weighted quantization errors [N*K] */ + const SKP_int *in_Q15, /* I Input vectors to be quantized [N*LPC_order] */ + const SKP_int *w_Q6, /* I Weighting vectors [N*LPC_order] */ + const SKP_int16 *pCB_Q15, /* I Codebook vectors [K*LPC_order] */ + const SKP_int N, /* I Number of input vectors */ + const SKP_int K, /* I Number of codebook vectors */ + const SKP_int LPC_order /* I Number of LPCs */ +) +{ + SKP_int i, n, m; + SKP_int32 diff_Q15, sum_error, Wtmp_Q6; + SKP_int32 Wcpy_Q6[ MAX_LPC_ORDER / 2 ]; + const SKP_int16 *cb_vec_Q15; + + SKP_assert( LPC_order <= 16 ); + SKP_assert( ( LPC_order & 1 ) == 0 ); + + /* Copy to local stack and pack two weights per int32 */ + for( m = 0; m < SKP_RSHIFT( LPC_order, 1 ); m++ ) { + Wcpy_Q6[ m ] = w_Q6[ 2 * m ] | SKP_LSHIFT( ( SKP_int32 )w_Q6[ 2 * m + 1 ], 16 ); + } + + /* Loop over input vectors */ + for( n = 0; n < N; n++ ) { + /* Loop over codebook */ + cb_vec_Q15 = pCB_Q15; + for( i = 0; i < K; i++ ) { + sum_error = 0; + for( m = 0; m < LPC_order; m += 2 ) { + /* Get two weights packed in an int32 */ + Wtmp_Q6 = Wcpy_Q6[ SKP_RSHIFT( m, 1 ) ]; + + /* Compute weighted squared quantization error for index m */ + diff_Q15 = in_Q15[ m ] - *cb_vec_Q15++; // range: [ -32767 : 32767 ] + sum_error = SKP_SMLAWB( sum_error, SKP_SMULBB( diff_Q15, diff_Q15 ), Wtmp_Q6 ); + + /* Compute weighted squared quantization error for index m + 1 */ + diff_Q15 = in_Q15[m + 1] - *cb_vec_Q15++; // range: [ -32767 : 32767 ] + sum_error = SKP_SMLAWT( sum_error, SKP_SMULBB( diff_Q15, diff_Q15 ), Wtmp_Q6 ); + } + SKP_assert( sum_error >= 0 ); + err_Q20[ i ] = sum_error; + } + err_Q20 += K; + in_Q15 += LPC_order; + } +} + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c new file mode 100644 index 0000000..71c3f23 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +#define Q_OUT 6 +#define MIN_NDELTA 3 + +/* Laroia low complexity NLSF weights */ +void SKP_Silk_NLSF_VQ_weights_laroia( + SKP_int *pNLSFW_Q6, /* O: Pointer to input vector weights [D x 1] */ + const SKP_int *pNLSF_Q15, /* I: Pointer to input vector [D x 1] */ + const SKP_int D /* I: Input vector dimension (even) */ +) +{ + SKP_int k; + SKP_int32 tmp1_int, tmp2_int; + + /* Check that we are guaranteed to end up within the required range */ + SKP_assert( D > 0 ); + SKP_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = SKP_max_int( pNLSF_Q15[ 0 ], MIN_NDELTA ); + tmp1_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp1_int ); + tmp2_int = SKP_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], MIN_NDELTA ); + tmp2_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp2_int ); + pNLSFW_Q6[ 0 ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = SKP_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], MIN_NDELTA ); + tmp1_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp1_int ); + pNLSFW_Q6[ k ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ k ] > 0 ); + + tmp2_int = SKP_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], MIN_NDELTA ); + tmp2_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp2_int ); + pNLSFW_Q6[ k + 1 ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = SKP_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], MIN_NDELTA ); + tmp1_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp1_int ); + pNLSFW_Q6[ D - 1 ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ D - 1 ] > 0 ); +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c b/pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c new file mode 100644 index 0000000..9fc2f61 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c @@ -0,0 +1,139 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs futher apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void SKP_Silk_NLSF_stabilize( + SKP_int *NLSF_Q15, /* I/O: Unstable/stabilized normalized LSF vector in Q15 [L] */ + const SKP_int *NDeltaMin_Q15, /* I: Normalized delta min vector in Q15, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const SKP_int L /* I: Number of NLSF parameters in the input vector */ +) +{ + SKP_int center_freq_Q15, diff_Q15, min_center_Q15, max_center_Q15; + SKP_int32 min_diff_Q15; + SKP_int loops; + SKP_int i, I=0, k; + + /* This is necessary to ensure an output within range of a SKP_int16 */ + SKP_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for( i = 1; i <= L-1; i++ ) { + diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = (1<<15) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if (min_diff_Q15 >= 0) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = (1<<15) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += SKP_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = (1<<15); + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= ( NDeltaMin_Q15[I] - SKP_RSHIFT( NDeltaMin_Q15[I], 1 ) ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = SKP_LIMIT_32( SKP_RSHIFT_ROUND( (SKP_int32)NLSF_Q15[I-1] + (SKP_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - SKP_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + SKP_Silk_insertion_sort_increasing_all_values(&NLSF_Q15[0], L); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = SKP_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = SKP_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = SKP_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = SKP_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_NSQ.c b/pkg/silk/csilk/SKP_Silk_NSQ.c new file mode 100644 index 0000000..3655cfe --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NSQ.c @@ -0,0 +1,454 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +SKP_INLINE void SKP_Silk_nsq_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I input in Q0 */ + SKP_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + SKP_int subfr_length, /* I length of input */ + const SKP_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I subframe number */ + const SKP_int LTP_scale_Q14, /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I */ +); + +SKP_INLINE void SKP_Silk_noise_shape_quantizer( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_sc_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int shapingLPCOrder, /* I Noise shaping AR filter order */ + SKP_int predictLPCOrder /* I Prediction filter order */ +); + +void SKP_Silk_NSQ( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I prefiltered input signal */ + SKP_int8 q[], /* O quantized qulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefficients */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I Long term prediction coefficients */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + SKP_int k, lag, start_idx, LSF_interpolation_flag; + const SKP_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + SKP_int16 *pxq; + SKP_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ]; + SKP_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 HarmShapeFIRPacked_Q14; + SKP_int offset_Q10; + SKP_int32 FiltState[ MAX_LPC_ORDER ]; + SKP_int32 x_sc_Q10[ MAX_FRAME_LENGTH / NB_SUBFR ]; + + NSQ->rand_seed = psEncCtrlC->Seed; + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + SKP_assert( NSQ->prev_inv_gain_Q16 != 0 ); + + offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrlC->sigtype ][ psEncCtrlC->QuantOffsetType ]; + + if( LSFInterpFactor_Q2 == ( 1 << 2 ) ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Setup pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->frame_length; + NSQ->sLTP_buf_idx = psEncC->frame_length; + pxq = &NSQ->xq[ psEncC->frame_length ]; + for( k = 0; k < NB_SUBFR; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + SKP_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = SKP_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= SKP_LSHIFT( ( SKP_int32 )SKP_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + /* Voiced */ + lag = psEncCtrlC->pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - SKP_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + + /* Rewhiten with new A coefs */ + start_idx = psEncC->frame_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + SKP_assert( start_idx >= 0 ); + SKP_assert( start_idx <= psEncC->frame_length - psEncC->predictLPCOrder ); + + SKP_memset( FiltState, 0, psEncC->predictLPCOrder * sizeof( SKP_int32 ) ); + SKP_Silk_MA_Prediction( &NSQ->xq[ start_idx + k * ( psEncC->frame_length >> 2 ) ], + A_Q12, FiltState, sLTP + start_idx, psEncC->frame_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->frame_length; + } + } + + SKP_Silk_nsq_scale_states( NSQ, x, x_sc_Q10, psEncC->subfr_length, sLTP, + sLTP_Q16, k, LTP_scale_Q14, Gains_Q16, psEncCtrlC->pitchL ); + + SKP_Silk_noise_shape_quantizer( NSQ, psEncCtrlC->sigtype, x_sc_Q10, q, pxq, sLTP_Q16, 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 + ); + + x += psEncC->subfr_length; + q += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = psEncCtrlC->pitchL[ NB_SUBFR - 1 ]; + + /* Save quantized speech and noise shaping signals */ + SKP_memcpy( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int16 ) ); + SKP_memcpy( NSQ->sLTP_shp_Q10, &NSQ->sLTP_shp_Q10[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int32 ) ); + +#ifdef USE_UNQUANTIZED_LSFS + DEBUG_STORE_DATA( xq_unq_lsfs.pcm, NSQ->xq, psEncC->frame_length * sizeof( SKP_int16 ) ); +#endif + +} + +/***********************************/ +/* SKP_Silk_noise_shape_quantizer */ +/***********************************/ +SKP_INLINE void SKP_Silk_noise_shape_quantizer( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_sc_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int shapingLPCOrder, /* I Noise shaping AR filter order */ + SKP_int predictLPCOrder /* I Prediction filter order */ +) +{ + SKP_int i, j; + SKP_int32 LTP_pred_Q14, LPC_pred_Q10, n_AR_Q10, n_LTP_Q14; + SKP_int32 n_LF_Q10, r_Q10, q_Q0, q_Q10; + SKP_int32 thr1_Q10, thr2_Q10, thr3_Q10; + SKP_int32 dither, exc_Q10, LPC_exc_Q10, xq_Q10; + SKP_int32 tmp1, tmp2, sLF_AR_shp_Q10; + SKP_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 a_Q12_tmp[ MAX_LPC_ORDER / 2 ], Atmp; + /* Preload LPC coefficients to array on stack. Gives small performance gain */ + SKP_memcpy( a_Q12_tmp, a_Q12, predictLPCOrder * sizeof( SKP_int16 ) ); +#endif + + shp_lag_ptr = &NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q16[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + + /* Setup short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + /* Quantization thresholds */ + thr1_Q10 = SKP_SUB_RSHIFT32( -1536, Lambda_Q10, 1 ); + thr2_Q10 = SKP_SUB_RSHIFT32( -512, Lambda_Q10, 1 ); + thr2_Q10 = SKP_ADD_RSHIFT32( thr2_Q10, SKP_SMULBB( offset_Q10, Lambda_Q10 ), 10 ); + thr3_Q10 = SKP_ADD_RSHIFT32( 512, Lambda_Q10, 1 ); + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = SKP_RAND( NSQ->rand_seed ); + + /* dither = rand_seed < 0 ? 0xFFFFFFFF : 0; */ + dither = SKP_RSHIFT( NSQ->rand_seed, 31 ); + + /* Short-term prediction */ + SKP_assert( ( predictLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* check that array starts at 4-byte aligned address */ + SKP_assert( ( ( SKP_int64 )( ( SKP_int8* )a_Q12 - ( SKP_int8* )0 ) & 3 ) == 0 ); + SKP_assert( predictLPCOrder >= 10 ); /* check that unrolling works */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + /* Partially unrolled */ + Atmp = a_Q12_tmp[ 0 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -1 ], Atmp ); + Atmp = a_Q12_tmp[ 1 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -3 ], Atmp ); + Atmp = a_Q12_tmp[ 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -5 ], Atmp ); + Atmp = a_Q12_tmp[ 3 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -7 ], Atmp ); + Atmp = a_Q12_tmp[ 4 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -9 ], Atmp ); + for( j = 10; j < predictLPCOrder; j += 2 ) { + Atmp = a_Q12_tmp[ j >> 1 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -j - 1 ], Atmp ); + } +#else + /* Partially unrolled */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + for( j = 10; j < predictLPCOrder; j ++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], a_Q12[ j ] ); + } +#endif + /* Long-term prediction */ + if( sigtype == SIG_TYPE_VOICED ) { + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Noise shape feedback */ + SKP_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + tmp2 = psLPC_Q14[ 0 ]; + tmp1 = NSQ->sAR2_Q14[ 0 ]; + NSQ->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q10 = SKP_SMULWB( tmp2, AR_shp_Q13[ 0 ] ); + for( j = 2; j < shapingLPCOrder; j += 2 ) { + tmp2 = NSQ->sAR2_Q14[ j - 1 ]; + NSQ->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ j - 1 ] ); + tmp1 = NSQ->sAR2_Q14[ j + 0 ]; + NSQ->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp2, AR_shp_Q13[ j ] ); + } + NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q10 = SKP_RSHIFT( n_AR_Q10, 1 ); /* Q11 -> Q10 */ + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, NSQ->sLF_AR_shp_Q12, Tilt_Q14 ); + + n_LF_Q10 = SKP_LSHIFT( SKP_SMULWB( NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ), 2 ); + n_LF_Q10 = SKP_SMLAWT( n_LF_Q10, NSQ->sLF_AR_shp_Q12, LF_shp_Q14 ); + + SKP_assert( lag > 0 || sigtype == SIG_TYPE_UNVOICED ); + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = SKP_SMULWB( SKP_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_LSHIFT( n_LTP_Q14, 6 ); + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + /* Input minus prediction plus noise feedback */ + //r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP; + tmp1 = SKP_SUB32( LTP_pred_Q14, n_LTP_Q14 ); /* Add Q14 stuff */ + tmp1 = SKP_RSHIFT( tmp1, 4 ); /* convert to Q10 */ + tmp1 = SKP_ADD32( tmp1, LPC_pred_Q10 ); /* add Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_AR_Q10 ); /* subtract Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_LF_Q10 ); /* subtract Q10 stuff */ + r_Q10 = SKP_SUB32( x_sc_Q10[ i ], tmp1 ); + + /* Flip sign depending on dither */ + r_Q10 = ( r_Q10 ^ dither ) - dither; + r_Q10 = SKP_SUB32( r_Q10, offset_Q10 ); + r_Q10 = SKP_LIMIT_32( r_Q10, -(64 << 10), 64 << 10 ); + + /* Quantize */ + q_Q0 = 0; + q_Q10 = 0; + if( r_Q10 < thr2_Q10 ) { + if( r_Q10 < thr1_Q10 ) { + q_Q0 = SKP_RSHIFT_ROUND( SKP_ADD_RSHIFT32( r_Q10, Lambda_Q10, 1 ), 10 ); + q_Q10 = SKP_LSHIFT( q_Q0, 10 ); + } else { + q_Q0 = -1; + q_Q10 = -1024; + } + } else { + if( r_Q10 > thr3_Q10 ) { + q_Q0 = SKP_RSHIFT_ROUND( SKP_SUB_RSHIFT32( r_Q10, Lambda_Q10, 1 ), 10 ); + q_Q10 = SKP_LSHIFT( q_Q0, 10 ); + } + } + q[ i ] = ( SKP_int8 )q_Q0; /* No saturation needed because max is 64 */ + + /* Excitation */ + exc_Q10 = SKP_ADD32( q_Q10, offset_Q10 ); + exc_Q10 = ( exc_Q10 ^ dither ) - dither; + + /* Add predictions */ + LPC_exc_Q10 = SKP_ADD32( exc_Q10, SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); + xq_Q10 = SKP_ADD32( LPC_exc_Q10, LPC_pred_Q10 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( xq_Q10, Gain_Q16 ), 10 ) ); + + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = SKP_LSHIFT( xq_Q10, 4 ); + sLF_AR_shp_Q10 = SKP_SUB32( xq_Q10, n_AR_Q10 ); + NSQ->sLF_AR_shp_Q12 = SKP_LSHIFT( sLF_AR_shp_Q10, 2 ); + + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx ] = SKP_SUB32( sLF_AR_shp_Q10, n_LF_Q10 ); + sLTP_Q16[ NSQ->sLTP_buf_idx ] = SKP_LSHIFT( LPC_exc_Q10, 6 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed += q[ i ]; + } + + /* Update LPC synth buffer */ + SKP_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); +} + +SKP_INLINE void SKP_Silk_nsq_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I input in Q0 */ + SKP_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + SKP_int subfr_length, /* I length of input */ + const SKP_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I subframe number */ + const SKP_int LTP_scale_Q14, /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I */ +) +{ + SKP_int i, lag; + SKP_int32 inv_gain_Q16, gain_adj_Q16, inv_gain_Q32; + + inv_gain_Q16 = SKP_INVERSE32_varQ( SKP_max( Gains_Q16[ subfr ], 1 ), 32 ); + inv_gain_Q16 = SKP_min( inv_gain_Q16, SKP_int16_MAX ); + lag = pitchL[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + inv_gain_Q32 = SKP_LSHIFT( inv_gain_Q16, 16 ); + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q32 = SKP_LSHIFT( SKP_SMULWB( inv_gain_Q32, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + SKP_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q16[ i ] = SKP_SMULWB( inv_gain_Q32, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( inv_gain_Q16 != NSQ->prev_inv_gain_Q16 ) { + gain_adj_Q16 = SKP_DIV32_varQ( inv_gain_Q16, NSQ->prev_inv_gain_Q16, 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - subfr_length * NB_SUBFR; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q10[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q10[ i ] ); + } + + /* Scale long-term prediction state */ + if( NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q16[ i ] = SKP_SMULWW( gain_adj_Q16, sLTP_Q16[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q12 = SKP_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q12 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } + + /* Scale input */ + for( i = 0; i < subfr_length; i++ ) { + x_sc_Q10[ i ] = SKP_RSHIFT( SKP_SMULBB( x[ i ], ( SKP_int16 )inv_gain_Q16 ), 6 ); + } + + /* save inv_gain */ + SKP_assert( inv_gain_Q16 != 0 ); + NSQ->prev_inv_gain_Q16 = inv_gain_Q16; +} diff --git a/pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c b/pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c new file mode 100644 index 0000000..16d0b20 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c @@ -0,0 +1,733 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +typedef struct { + SKP_int32 RandState[ DECISION_DELAY ]; + SKP_int32 Q_Q10[ DECISION_DELAY ]; + SKP_int32 Xq_Q10[ DECISION_DELAY ]; + SKP_int32 Pred_Q16[ DECISION_DELAY ]; + SKP_int32 Shape_Q10[ DECISION_DELAY ]; + SKP_int32 Gain_Q16[ DECISION_DELAY ]; + SKP_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 sLPC_Q14[ MAX_FRAME_LENGTH / NB_SUBFR + NSQ_LPC_BUF_LENGTH ]; + SKP_int32 LF_AR_Q12; + SKP_int32 Seed; + SKP_int32 SeedInit; + SKP_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + SKP_int32 Q_Q10; + SKP_int32 RD_Q10; + SKP_int32 xq_Q14; + SKP_int32 LF_AR_Q12; + SKP_int32 sLTP_shp_Q10; + SKP_int32 LPC_exc_Q16; +} NSQ_sample_struct; + +SKP_INLINE void SKP_Silk_copy_del_dec_state( + NSQ_del_dec_struct *DD_dst, /* I Dst del dec state */ + NSQ_del_dec_struct *DD_src, /* I Src del dec state */ + SKP_int LPC_state_idx /* I Index to LPC buffer */ +); + +SKP_INLINE void SKP_Silk_nsq_del_dec_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const SKP_int16 x[], /* I Input in Q0 */ + SKP_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + SKP_int subfr_length, /* I Length of input */ + const SKP_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I Subframe number */ + SKP_int nStatesDelayedDecision, /* I Number of del dec states */ + SKP_int smpl_buf_idx, /* I Index to newest samples in buffers */ + const SKP_int LTP_scale_Q14, /* I LTP state scaling */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I Pitch lag */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +SKP_INLINE void SKP_Silk_noise_shape_quantizer_del_dec( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP filter state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int subfr, /* I Subframe number */ + SKP_int shapingLPCOrder, /* I Shaping LPC filter order */ + SKP_int predictLPCOrder, /* I Prediction filter order */ + SKP_int warping_Q16, /* I */ + SKP_int nStatesDelayedDecision, /* I Number of states in decision tree */ + SKP_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + SKP_int decisionDelay /* I */ +); + +void SKP_Silk_NSQ_del_dec( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I Prefiltered input signal */ + SKP_int8 q[], /* O Quantized pulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Prediction coefs */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I LT prediction coefs */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + SKP_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + SKP_int last_smple_idx, smpl_buf_idx, decisionDelay, subfr_length; + const SKP_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + SKP_int16 *pxq; + SKP_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ]; + SKP_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 HarmShapeFIRPacked_Q14; + SKP_int offset_Q10; + SKP_int32 FiltState[ MAX_LPC_ORDER ], RDmin_Q10; + SKP_int32 x_sc_Q10[ MAX_FRAME_LENGTH / NB_SUBFR ]; + NSQ_del_dec_struct psDelDec[ MAX_DEL_DEC_STATES ]; + NSQ_del_dec_struct *psDD; + + subfr_length = psEncC->frame_length / NB_SUBFR; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + SKP_assert( NSQ->prev_inv_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + SKP_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psEncCtrlC->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q12 = NSQ->sLF_AR_shp_Q12; + psDD->Shape_Q10[ 0 ] = NSQ->sLTP_shp_Q10[ psEncC->frame_length - 1 ]; + SKP_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + SKP_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrlC->sigtype ][ psEncCtrlC->QuantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = SKP_min_int( DECISION_DELAY, subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + for( k = 0; k < NB_SUBFR; k++ ) { + decisionDelay = SKP_min_int( decisionDelay, psEncCtrlC->pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = SKP_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( LSFInterpFactor_Q2 == ( 1 << 2 ) ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Setup pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->frame_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->frame_length; + NSQ->sLTP_buf_idx = psEncC->frame_length; + subfr = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + SKP_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = SKP_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= SKP_LSHIFT( ( SKP_int32 )SKP_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + /* Voiced */ + lag = psEncCtrlC->pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - SKP_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 += ( SKP_int32_MAX >> 4 ); + SKP_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_MASK; + q[ i - decisionDelay ] = ( SKP_int8 )SKP_RSHIFT( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( + SKP_SMULWW( psDD->Xq_Q10[ last_smple_idx ], + psDD->Gain_Q16[ last_smple_idx ] ), 10 ) ); + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q10[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->frame_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + SKP_assert( start_idx >= 0 ); + SKP_assert( start_idx <= psEncC->frame_length - psEncC->predictLPCOrder ); + + SKP_memset( FiltState, 0, psEncC->predictLPCOrder * sizeof( SKP_int32 ) ); + SKP_Silk_MA_Prediction( &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, FiltState, sLTP + start_idx, psEncC->frame_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->sLTP_buf_idx = psEncC->frame_length; + NSQ->rewhite_flag = 1; + } + } + + SKP_Silk_nsq_del_dec_scale_states( NSQ, psDelDec, x, x_sc_Q10, + subfr_length, sLTP, sLTP_Q16, k, psEncC->nStatesDelayedDecision, smpl_buf_idx, + LTP_scale_Q14, Gains_Q16, psEncCtrlC->pitchL ); + + SKP_Silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psEncCtrlC->sigtype, x_sc_Q10, q, pxq, sLTP_Q16, + A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], + Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, + psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay ); + + x += psEncC->subfr_length; + q += 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 ]; + psEncCtrlC->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; + q[ i - decisionDelay ] = ( SKP_int8 )SKP_RSHIFT( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( + SKP_SMULWW( psDD->Xq_Q10[ last_smple_idx ], psDD->Gain_Q16[ last_smple_idx ] ), 10 ) ); + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q10[ last_smple_idx ]; + sLTP_Q16[ NSQ->sLTP_buf_idx - decisionDelay + i ] = psDD->Pred_Q16[ last_smple_idx ]; + } + SKP_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + SKP_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q12 = psDD->LF_AR_Q12; + NSQ->lagPrev = psEncCtrlC->pitchL[ NB_SUBFR - 1 ]; + + /* Save quantized speech and noise shaping signals */ + SKP_memcpy( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int16 ) ); + SKP_memcpy( NSQ->sLTP_shp_Q10, &NSQ->sLTP_shp_Q10[ psEncC->frame_length ], psEncC->frame_length * sizeof( SKP_int32 ) ); + +#ifdef USE_UNQUANTIZED_LSFS + DEBUG_STORE_DATA( xq_unq_lsfs.pcm, NSQ->xq, psEncC->frame_length * sizeof( SKP_int16 ) ); +#endif + +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +SKP_INLINE void SKP_Silk_noise_shape_quantizer_del_dec( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + SKP_int sigtype, /* I Signal type */ + const SKP_int32 x_Q10[], /* I */ + SKP_int8 q[], /* O */ + SKP_int16 xq[], /* O */ + SKP_int32 sLTP_Q16[], /* I/O LTP filter state */ + const SKP_int16 a_Q12[], /* I Short term prediction coefs */ + const SKP_int16 b_Q14[], /* I Long term prediction coefs */ + const SKP_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + SKP_int lag, /* I Pitch lag */ + SKP_int32 HarmShapeFIRPacked_Q14, /* I */ + SKP_int Tilt_Q14, /* I Spectral tilt */ + SKP_int32 LF_shp_Q14, /* I */ + SKP_int32 Gain_Q16, /* I */ + SKP_int Lambda_Q10, /* I */ + SKP_int offset_Q10, /* I */ + SKP_int length, /* I Input length */ + SKP_int subfr, /* I Subframe number */ + SKP_int shapingLPCOrder, /* I Shaping LPC filter order */ + SKP_int predictLPCOrder, /* I Prediction filter order */ + SKP_int warping_Q16, /* I */ + SKP_int nStatesDelayedDecision, /* I Number of states in decision tree */ + SKP_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + SKP_int decisionDelay /* I */ +) +{ + SKP_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + SKP_int32 Winner_rand_state; + SKP_int32 LTP_pred_Q14, LPC_pred_Q10, n_AR_Q10, n_LTP_Q14; + SKP_int32 n_LF_Q10, r_Q10, rr_Q20, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + SKP_int32 q1_Q10, q2_Q10, dither, exc_Q10, LPC_exc_Q10, xq_Q10; + SKP_int32 tmp1, tmp2, sLF_AR_shp_Q10; + SKP_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; + NSQ_sample_struct psSampleState[ MAX_DEL_DEC_STATES ][ 2 ]; + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 a_Q12_tmp[ MAX_LPC_ORDER / 2 ], Atmp; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + SKP_memcpy( a_Q12_tmp, a_Q12, predictLPCOrder * sizeof( SKP_int16 ) ); +#endif + + shp_lag_ptr = &NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q16[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( sigtype == SIG_TYPE_VOICED ) { + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = SKP_SMULWB( SKP_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = SKP_LSHIFT( n_LTP_Q14, 6 ); + 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 = SKP_RAND( psDD->Seed ); + + /* dither = rand_seed < 0 ? 0xFFFFFFFF : 0; */ + dither = SKP_RSHIFT( psDD->Seed, 31 ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + SKP_assert( predictLPCOrder >= 10 ); /* check that unrolling works */ + SKP_assert( ( predictLPCOrder & 1 ) == 0 ); /* check that order is even */ + SKP_assert( ( ( ( int )( ( char* )( a_Q12 ) - ( ( char* ) 0 ) ) ) & 3 ) == 0 ); /* check that array starts at 4-byte aligned address */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* Partially unrolled */ + Atmp = a_Q12_tmp[ 0 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -1 ], Atmp ); + Atmp = a_Q12_tmp[ 1 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -3 ], Atmp ); + Atmp = a_Q12_tmp[ 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -5 ], Atmp ); + Atmp = a_Q12_tmp[ 3 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -7 ], Atmp ); + Atmp = a_Q12_tmp[ 4 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -9 ], Atmp ); + for( j = 10; j < predictLPCOrder; j += 2 ) { + Atmp = a_Q12_tmp[ j >> 1 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -j - 1 ], Atmp ); + } +#else + /* Partially unrolled */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + for( j = 10; j < predictLPCOrder; j ++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], a_Q12[ j ] ); + } +#endif + + /* Noise shape feedback */ + SKP_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = SKP_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q10 = SKP_SMULWB( tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = SKP_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q10 = SKP_RSHIFT( n_AR_Q10, 1 ); /* Q11 -> Q10 */ + n_AR_Q10 = SKP_SMLAWB( n_AR_Q10, psDD->LF_AR_Q12, Tilt_Q14 ); + + n_LF_Q10 = SKP_LSHIFT( SKP_SMULWB( psDD->Shape_Q10[ *smpl_buf_idx ], LF_shp_Q14 ), 2 ); + n_LF_Q10 = SKP_SMLAWT( n_LF_Q10, psDD->LF_AR_Q12, LF_shp_Q14 ); + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = SKP_SUB32( LTP_pred_Q14, n_LTP_Q14 ); /* Add Q14 stuff */ + tmp1 = SKP_RSHIFT( tmp1, 4 ); /* convert to Q10 */ + tmp1 = SKP_ADD32( tmp1, LPC_pred_Q10 ); /* add Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_AR_Q10 ); /* subtract Q10 stuff */ + tmp1 = SKP_SUB32( tmp1, n_LF_Q10 ); /* subtract Q10 stuff */ + r_Q10 = SKP_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + r_Q10 = ( r_Q10 ^ dither ) - dither; + r_Q10 = SKP_SUB32( r_Q10, offset_Q10 ); + r_Q10 = SKP_LIMIT_32( r_Q10, -(64 << 10), 64 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + if( r_Q10 < -1536 ) { + q1_Q10 = SKP_LSHIFT( SKP_RSHIFT_ROUND( r_Q10, 10 ), 10 ); + r_Q10 = SKP_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = SKP_RSHIFT( SKP_SMLABB( SKP_MUL( -SKP_ADD32( q1_Q10, offset_Q10 ), Lambda_Q10 ), r_Q10, r_Q10 ), 10 ); + rd2_Q10 = SKP_ADD32( rd1_Q10, 1024 ); + rd2_Q10 = SKP_SUB32( rd2_Q10, SKP_ADD_LSHIFT32( Lambda_Q10, r_Q10, 1 ) ); + q2_Q10 = SKP_ADD32( q1_Q10, 1024 ); + } else if( r_Q10 > 512 ) { + q1_Q10 = SKP_LSHIFT( SKP_RSHIFT_ROUND( r_Q10, 10 ), 10 ); + r_Q10 = SKP_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = SKP_RSHIFT( SKP_SMLABB( SKP_MUL( SKP_ADD32( q1_Q10, offset_Q10 ), Lambda_Q10 ), r_Q10, r_Q10 ), 10 ); + rd2_Q10 = SKP_ADD32( rd1_Q10, 1024 ); + rd2_Q10 = SKP_SUB32( rd2_Q10, SKP_SUB_LSHIFT32( Lambda_Q10, r_Q10, 1 ) ); + q2_Q10 = SKP_SUB32( q1_Q10, 1024 ); + } else { /* r_Q10 >= -1536 && q1_Q10 <= 512 */ + rr_Q20 = SKP_SMULBB( offset_Q10, Lambda_Q10 ); + rd2_Q10 = SKP_RSHIFT( SKP_SMLABB( rr_Q20, r_Q10, r_Q10 ), 10 ); + rd1_Q10 = SKP_ADD32( rd2_Q10, 1024 ); + rd1_Q10 = SKP_ADD32( rd1_Q10, SKP_SUB_RSHIFT32( SKP_ADD_LSHIFT32( Lambda_Q10, r_Q10, 1 ), rr_Q20, 9 ) ); + q1_Q10 = -1024; + q2_Q10 = 0; + } + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = SKP_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = SKP_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_Q10 = SKP_ADD32( offset_Q10, psSS[ 0 ].Q_Q10 ); + exc_Q10 = ( exc_Q10 ^ dither ) - dither; + + /* Add predictions */ + LPC_exc_Q10 = exc_Q10 + SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ); + xq_Q10 = SKP_ADD32( LPC_exc_Q10, LPC_pred_Q10 ); + + /* Update states */ + sLF_AR_shp_Q10 = SKP_SUB32( xq_Q10, n_AR_Q10 ); + psSS[ 0 ].sLTP_shp_Q10 = SKP_SUB32( sLF_AR_shp_Q10, n_LF_Q10 ); + psSS[ 0 ].LF_AR_Q12 = SKP_LSHIFT( sLF_AR_shp_Q10, 2 ); + psSS[ 0 ].xq_Q14 = SKP_LSHIFT( xq_Q10, 4 ); + psSS[ 0 ].LPC_exc_Q16 = SKP_LSHIFT( LPC_exc_Q10, 6 ); + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q10 = SKP_ADD32( offset_Q10, psSS[ 1 ].Q_Q10 ); + exc_Q10 = ( exc_Q10 ^ dither ) - dither; + + /* Add predictions */ + LPC_exc_Q10 = exc_Q10 + SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ); + xq_Q10 = SKP_ADD32( LPC_exc_Q10, LPC_pred_Q10 ); + + /* Update states */ + sLF_AR_shp_Q10 = SKP_SUB32( xq_Q10, n_AR_Q10 ); + psSS[ 1 ].sLTP_shp_Q10 = SKP_SUB32( sLF_AR_shp_Q10, n_LF_Q10 ); + psSS[ 1 ].LF_AR_Q12 = SKP_LSHIFT( sLF_AR_shp_Q10, 2 ); + psSS[ 1 ].xq_Q14 = SKP_LSHIFT( xq_Q10, 4 ); + psSS[ 1 ].LPC_exc_Q16 = SKP_LSHIFT( LPC_exc_Q10, 6 ); + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */ + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */ + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + 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 = SKP_ADD32( psSampleState[ k ][ 0 ].RD_Q10, ( SKP_int32_MAX >> 4 ) ); + psSampleState[ k ][ 1 ].RD_Q10 = SKP_ADD32( psSampleState[ k ][ 1 ].RD_Q10, ( SKP_int32_MAX >> 4 ) ); + SKP_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 ) { + SKP_Silk_copy_del_dec_state( &psDelDec[ RDmax_ind ], &psDelDec[ RDmin_ind ], i ); + SKP_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 ) { + q[ i - decisionDelay ] = ( SKP_int8 )SKP_RSHIFT( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( + SKP_SMULWW( psDD->Xq_Q10[ last_smple_idx ], psDD->Gain_Q16[ last_smple_idx ] ), 10 ) ); + NSQ->sLTP_shp_Q10[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q10[ last_smple_idx ]; + sLTP_Q16[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q16[ 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_Q12 = psSS->LF_AR_Q12; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q10[ *smpl_buf_idx ] = SKP_RSHIFT( psSS->xq_Q14, 4 ); + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q16[ *smpl_buf_idx ] = psSS->LPC_exc_Q16; + psDD->Shape_Q10[ *smpl_buf_idx ] = psSS->sLTP_shp_Q10; + psDD->Seed = SKP_ADD_RSHIFT32( psDD->Seed, psSS->Q_Q10, 10 ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + psDD->Gain_Q16[ *smpl_buf_idx ] = Gain_Q16; + } + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + SKP_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + } +} + +SKP_INLINE void SKP_Silk_nsq_del_dec_scale_states( + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const SKP_int16 x[], /* I Input in Q0 */ + SKP_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + SKP_int subfr_length, /* I Length of input */ + const SKP_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + SKP_int32 sLTP_Q16[], /* O LTP state matching scaled input */ + SKP_int subfr, /* I Subframe number */ + SKP_int nStatesDelayedDecision, /* I Number of del dec states */ + SKP_int smpl_buf_idx, /* I Index to newest samples in buffers */ + const SKP_int LTP_scale_Q14, /* I LTP state scaling */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int pitchL[ NB_SUBFR ] /* I Pitch lag */ +) +{ + SKP_int i, k, lag; + SKP_int32 inv_gain_Q16, gain_adj_Q16, inv_gain_Q32; + NSQ_del_dec_struct *psDD; + + inv_gain_Q16 = SKP_INVERSE32_varQ( SKP_max( Gains_Q16[ subfr ], 1 ), 32 ); + inv_gain_Q16 = SKP_min( inv_gain_Q16, SKP_int16_MAX ); + lag = pitchL[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + inv_gain_Q32 = SKP_LSHIFT( inv_gain_Q16, 16 ); + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q32 = SKP_LSHIFT( SKP_SMULWB( inv_gain_Q32, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + SKP_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q16[ i ] = SKP_SMULWB( inv_gain_Q32, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( inv_gain_Q16 != NSQ->prev_inv_gain_Q16 ) { + gain_adj_Q16 = SKP_DIV32_varQ( inv_gain_Q16, NSQ->prev_inv_gain_Q16, 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - subfr_length * NB_SUBFR; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q10[ i ] = SKP_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q10[ i ] ); + } + + /* Scale long-term prediction state */ + if( NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q16[ i ] = SKP_SMULWW( gain_adj_Q16, sLTP_Q16[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q12 = SKP_SMULWW( gain_adj_Q16, psDD->LF_AR_Q12 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q16[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->Pred_Q16[ i ] ); + psDD->Shape_Q10[ i ] = SKP_SMULWW( gain_adj_Q16, psDD->Shape_Q10[ i ] ); + } + } + } + + /* Scale input */ + for( i = 0; i < subfr_length; i++ ) { + x_sc_Q10[ i ] = SKP_RSHIFT( SKP_SMULBB( x[ i ], ( SKP_int16 )inv_gain_Q16 ), 6 ); + } + + /* save inv_gain */ + SKP_assert( inv_gain_Q16 != 0 ); + NSQ->prev_inv_gain_Q16 = inv_gain_Q16; +} + +SKP_INLINE void SKP_Silk_copy_del_dec_state( + NSQ_del_dec_struct *DD_dst, /* I Dst del dec state */ + NSQ_del_dec_struct *DD_src, /* I Src del dec state */ + SKP_int LPC_state_idx /* I Index to LPC buffer */ +) +{ + SKP_memcpy( DD_dst->RandState, DD_src->RandState, sizeof( DD_src->RandState ) ); + SKP_memcpy( DD_dst->Q_Q10, DD_src->Q_Q10, sizeof( DD_src->Q_Q10 ) ); + SKP_memcpy( DD_dst->Pred_Q16, DD_src->Pred_Q16, sizeof( DD_src->Pred_Q16 ) ); + SKP_memcpy( DD_dst->Shape_Q10, DD_src->Shape_Q10, sizeof( DD_src->Shape_Q10 ) ); + SKP_memcpy( DD_dst->Xq_Q10, DD_src->Xq_Q10, sizeof( DD_src->Xq_Q10 ) ); + SKP_memcpy( DD_dst->sAR2_Q14, DD_src->sAR2_Q14, sizeof( DD_src->sAR2_Q14 ) ); + SKP_memcpy( &DD_dst->sLPC_Q14[ LPC_state_idx ], &DD_src->sLPC_Q14[ LPC_state_idx ], NSQ_LPC_BUF_LENGTH * sizeof( SKP_int32 ) ); + DD_dst->LF_AR_Q12 = DD_src->LF_AR_Q12; + DD_dst->Seed = DD_src->Seed; + DD_dst->SeedInit = DD_src->SeedInit; + DD_dst->RD_Q10 = DD_src->RD_Q10; +} diff --git a/pkg/silk/csilk/SKP_Silk_PLC.c b/pkg/silk/csilk/SKP_Silk_PLC.c new file mode 100644 index 0000000..8058610 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_PLC.c @@ -0,0 +1,418 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" +#include "SKP_Silk_PLC.h" + +#define NB_ATT 2 +static const SKP_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const SKP_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const SKP_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +void SKP_Silk_PLC_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = SKP_RSHIFT( psDec->frame_length, 1 ); +} + +void SKP_Silk_PLC( + SKP_Silk_decoder_state *psDec, /* I Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I Decoder control */ + SKP_int16 signal[], /* O Concealed signal */ + SKP_int length, /* I length of residual */ + SKP_int lost /* I Loss flag */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + SKP_Silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + SKP_Silk_PLC_conceal( psDec, psDecCtrl, signal, length ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + SKP_Silk_PLC_update( psDec, psDecCtrl, signal, length ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +void SKP_Silk_PLC_update( + SKP_Silk_decoder_state *psDec, /* (I/O) Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* (I/O) Decoder control */ + SKP_int16 signal[], + SKP_int length +) +{ + SKP_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + SKP_int i, j; + SKP_Silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prev_sigtype = psDecCtrl->sigtype; + LTP_Gain_Q14 = 0; + if( psDecCtrl->sigtype == SIG_TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ NB_SUBFR - 1 ]; j++ ) { + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( NB_SUBFR - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + SKP_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ SKP_SMULBB( NB_SUBFR - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( SKP_int16 ) ); + + psPLC->pitchL_Q8 = SKP_LSHIFT( psDecCtrl->pitchL[ NB_SUBFR - 1 - j ], 8 ); + } + } + +#if USE_SINGLE_TAP + SKP_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( SKP_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; +#endif + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + SKP_int scale_Q10; + SKP_int32 tmp; + + tmp = SKP_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = SKP_DIV32( tmp, SKP_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = SKP_RSHIFT( SKP_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + SKP_int scale_Q14; + SKP_int32 tmp; + + tmp = SKP_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = SKP_DIV32( tmp, SKP_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = SKP_RSHIFT( SKP_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = SKP_LSHIFT( SKP_SMULBB( psDec->fs_kHz, 18 ), 8 ); + SKP_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( SKP_int16 )); + } + + /* Save LPC coeficients */ + SKP_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( SKP_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save Gains */ + SKP_memcpy( psPLC->prevGain_Q16, psDecCtrl->Gains_Q16, NB_SUBFR * sizeof( SKP_int32 ) ); +} + +void SKP_Silk_PLC_conceal( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* O concealed signal */ + SKP_int length /* I length of residual */ +) +{ + SKP_int i, j, k; + SKP_int16 *B_Q14, exc_buf[ MAX_FRAME_LENGTH ], *exc_buf_ptr; + SKP_int16 rand_scale_Q14; + union { + SKP_int16 as_int16[ MAX_LPC_ORDER ]; + SKP_int32 as_int32[ MAX_LPC_ORDER / 2 ]; + } A_Q12_tmp; + SKP_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15; + SKP_int lag, idx, sLTP_buf_idx, shift1, shift2; + SKP_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + SKP_int32 sig_Q10[ MAX_FRAME_LENGTH ], *sig_Q10_ptr, LPC_exc_Q10, LPC_pred_Q10, LTP_pred_Q14; + SKP_Silk_PLC_struct *psPLC; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp; +#endif + psPLC = &psDec->sPLC; + + /* Update LTP buffer */ + SKP_memcpy( psDec->sLTP_Q16, &psDec->sLTP_Q16[ psDec->frame_length ], psDec->frame_length * sizeof( SKP_int32 ) ); + + /* LPC concealment. Apply BWE to previous LPC */ + SKP_Silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, BWE_COEF_Q16 ); + + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = ( NB_SUBFR >> 1 ); k < NB_SUBFR; k++ ) { + for( i = 0; i < psDec->subfr_length; i++ ) { + exc_buf_ptr[ i ] = ( SKP_int16 )SKP_RSHIFT( + SKP_SMULWW( psDec->exc_Q10[ i + k * psDec->subfr_length ], psPLC->prevGain_Q16[ k ] ), 10 ); + } + exc_buf_ptr += psDec->subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + SKP_Silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psDec->subfr_length ); + SKP_Silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psDec->subfr_length ], psDec->subfr_length ); + + if( SKP_RSHIFT( energy1, shift2 ) < SKP_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, 3 * psDec->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q10[ SKP_max_int( 0, psDec->frame_length - RAND_BUF_SIZE ) ]; + } + + /* Setup Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Setup attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prev_sigtype == SIG_TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ SKP_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = (1 << 14 ); + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prev_sigtype == SIG_TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = SKP_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = ( SKP_int16 )SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } + + /* Reduce random noise for unvoiced frames with high LPC gain */ + if( psDec->prev_sigtype == SIG_TYPE_UNVOICED ) { + SKP_int32 invGain_Q30, down_scale_Q30; + + SKP_Silk_LPC_inverse_pred_gain( &invGain_Q30, psPLC->prevLPC_Q12, psDec->LPC_order ); + + down_scale_Q30 = SKP_min_32( SKP_RSHIFT( ( 1 << 30 ), LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = SKP_max_32( SKP_RSHIFT( ( 1 << 30 ), LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = SKP_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = SKP_RSHIFT( SKP_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->frame_length; + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + sig_Q10_ptr = sig_Q10; + for( k = 0; k < NB_SUBFR; k++ ) { + /* Setup pointer */ + pred_lag_ptr = &psDec->sLTP_Q16[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + rand_seed = SKP_RAND( rand_seed ); + idx = SKP_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC residual */ + LPC_exc_Q10 = SKP_LSHIFT( SKP_SMULWB( rand_ptr[ idx ], rand_scale_Q14 ), 2 ); /* Random noise part */ + LPC_exc_Q10 = SKP_ADD32( LPC_exc_Q10, SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); /* Harmonic part */ + + /* Update states */ + psDec->sLTP_Q16[ sLTP_buf_idx ] = SKP_LSHIFT( LPC_exc_Q10, 6 ); + sLTP_buf_idx++; + + /* Save LPC residual */ + sig_Q10_ptr[ i ] = LPC_exc_Q10; + } + sig_Q10_ptr += psDec->subfr_length; + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = SKP_RSHIFT( SKP_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + /* Gradually reduce excitation gain */ + rand_scale_Q14 = SKP_RSHIFT( SKP_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 += SKP_SMULWB( psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = SKP_min_32( psPLC->pitchL_Q8, SKP_LSHIFT( SKP_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = SKP_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sig_Q10_ptr = sig_Q10; + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + SKP_memcpy( A_Q12_tmp.as_int16, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( SKP_int16 ) ); + SKP_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( k = 0; k < NB_SUBFR; k++ ) { + for( i = 0; i < psDec->subfr_length; i++ ){ + /* partly unrolled */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + Atmp = A_Q12_tmp.as_int32[ 0 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 1 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 3 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 4 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); + for( j = 10 ; j < psDec->LPC_order ; j+=2 ) { + Atmp = A_Q12_tmp.as_int32[ j / 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 - j ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 - j ], Atmp ); + } +#else + LPC_pred_Q10 = SKP_SMULWB( psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp.as_int16[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp.as_int16[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp.as_int16[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp.as_int16[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp.as_int16[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp.as_int16[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp.as_int16[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp.as_int16[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp.as_int16[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp.as_int16[ 9 ] ); + + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - j - 1 ], A_Q12_tmp.as_int16[ j ] ); + } +#endif + /* Add prediction to LPC residual */ + sig_Q10_ptr[ i ] = SKP_ADD32( sig_Q10_ptr[ i ], LPC_pred_Q10 ); + + /* Update states */ + psDec->sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT( sig_Q10_ptr[ i ], 4 ); + } + sig_Q10_ptr += psDec->subfr_length; + /* Update LPC filter state */ + SKP_memcpy( psDec->sLPC_Q14, &psDec->sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( SKP_int32 ) ); + } + + /* Scale with Gain */ + for( i = 0; i < psDec->frame_length; i++ ) { + signal[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( sig_Q10[ i ], psPLC->prevGain_Q16[ NB_SUBFR - 1 ] ), 10 ) ); + } + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } +} + +/* Glues concealed frames with new good recieved frames */ +void SKP_Silk_PLC_glue_frames( + SKP_Silk_decoder_state *psDec, /* I/O decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O signal */ + SKP_int length /* I length of residual */ +) +{ + SKP_int i, energy_shift; + SKP_int32 energy; + SKP_Silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + SKP_Silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, signal, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + SKP_Silk_sum_sqr_shift( &energy, &energy_shift, signal, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = SKP_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = SKP_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + SKP_int32 frac_Q24, LZ; + SKP_int32 gain_Q12, slope_Q12; + + LZ = SKP_Silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = SKP_LSHIFT( psPLC->conc_energy, LZ ); + energy = SKP_RSHIFT( energy, SKP_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = SKP_DIV32( psPLC->conc_energy, SKP_max( energy, 1 ) ); + + gain_Q12 = SKP_Silk_SQRT_APPROX( frac_Q24 ); + slope_Q12 = SKP_DIV32_16( ( 1 << 12 ) - gain_Q12, length ); + + for( i = 0; i < length; i++ ) { + signal[ i ] = SKP_RSHIFT( SKP_MUL( gain_Q12, signal[ i ] ), 12 ); + gain_Q12 += slope_Q12; + gain_Q12 = SKP_min( gain_Q12, ( 1 << 12 ) ); + } + } + } + psPLC->last_frame_lost = 0; + + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_PLC.h b/pkg/silk/csilk/SKP_Silk_PLC.h new file mode 100644 index 0000000..1723943 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_PLC.h @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_PLC_FIX_H +#define SKP_SILK_PLC_FIX_H + +#include "SKP_Silk_main.h" + +#define BWE_COEF_Q16 64880 /* 0.99 in Q16 */ +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define SA_THRES_Q8 50 +#define USE_SINGLE_TAP 1 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK (RAND_BUF_SIZE - 1) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void SKP_Silk_PLC_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +); + +void SKP_Silk_PLC( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O signal */ + SKP_int length, /* I length of residual */ + SKP_int lost /* I Loss flag */ +); + +void SKP_Silk_PLC_update( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], + SKP_int length +); + +void SKP_Silk_PLC_conceal( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* O LPC residual signal */ + SKP_int length /* I length of signal */ +); + +void SKP_Silk_PLC_glue_frames( + SKP_Silk_decoder_state *psDec, /* I/O decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O signal */ + SKP_int length /* I length of signal */ +); + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_SDK_API.h b/pkg/silk/csilk/SKP_Silk_SDK_API.h new file mode 100644 index 0000000..0e9041b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_SDK_API.h @@ -0,0 +1,152 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_SDK_API_H +#define SKP_SILK_SDK_API_H + +#include "SKP_Silk_control.h" +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_errors.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 5 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + SKP_int framesInPacket; /* Number of 20 ms frames in packet */ + SKP_int fs_kHz; /* Sampling frequency in packet */ + SKP_int inbandLBRR; /* Does packet contain LBRR information */ + SKP_int corrupt; /* Packet is corrupt */ + SKP_int vadFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* VAD flag for each frame in packet */ + SKP_int sigtypeFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Signal type for each frame in packet */ +} SKP_Silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +SKP_int SKP_Silk_SDK_Get_Encoder_Size( + SKP_int32 *encSizeBytes /* O: Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +SKP_int SKP_Silk_SDK_InitEncoder( + void *encState, /* I/O: State */ + SKP_SILK_SDK_EncControlStruct *encStatus /* O: Encoder Status */ +); + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +SKP_int SKP_Silk_SDK_QueryEncoder( + const void *encState, /* I: State */ + SKP_SILK_SDK_EncControlStruct *encStatus /* O: Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +SKP_int SKP_Silk_SDK_Encode( + void *encState, /* I/O: State */ + const SKP_SILK_SDK_EncControlStruct *encControl, /* I: Control status */ + const SKP_int16 *samplesIn, /* I: Speech sample input vector */ + SKP_int nSamplesIn, /* I: Number of samples in input vector */ + SKP_uint8 *outData, /* O: Encoded output vector */ + SKP_int16 *nBytesOut /* I/O: Number of bytes in outData (input: Max bytes) */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +SKP_int SKP_Silk_SDK_Get_Decoder_Size( + SKP_int32 *decSizeBytes /* O: Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +SKP_int SKP_Silk_SDK_InitDecoder( + void *decState /* I/O: State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +SKP_int SKP_Silk_SDK_Decode( + void* decState, /* I/O: State */ + SKP_SILK_SDK_DecControlStruct* decControl, /* I/O: Control Structure */ + SKP_int lostFlag, /* I: 0: no loss, 1 loss */ + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input bytes */ + SKP_int16 *samplesOut, /* O: Decoded output speech vector */ + SKP_int16 *nSamplesOut /* I/O: Number of samples (vector/decoded) */ +); + +/***************************************************************/ +/* Find Low Bit Rate Redundancy (LBRR) information in a packet */ +/***************************************************************/ +void SKP_Silk_SDK_search_for_LBRR( + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input Bytes */ + SKP_int lost_offset, /* I: Offset from lost packet */ + SKP_uint8 *LBRRData, /* O: LBRR payload */ + SKP_int16 *nLBRRBytes /* O: Number of LBRR Bytes */ +); + +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +void SKP_Silk_SDK_get_TOC( + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input bytes */ + SKP_Silk_TOC_struct *Silk_TOC /* O: Table of contents */ +); + +/**************************/ +/* Get the version number */ +/**************************/ +/* Return a pointer to string specifying the version */ +const char *SKP_Silk_SDK_get_version(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_SigProc_FIX.h b/pkg/silk/csilk/SKP_Silk_SigProc_FIX.h new file mode 100644 index 0000000..d53cb40 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_SigProc_FIX.h @@ -0,0 +1,663 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _SKP_SILK_SIGPROC_FIX_H_ +#define _SKP_SILK_SIGPROC_FIX_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SKP_Silk_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */ +#define SKP_Silk_MAX_CORRELATION_LENGTH 640 /* max input length to the correlation */ +#include "SKP_Silk_typedef.h" +#include +#include /* for abs() */ +#include "SKP_Silk_resampler_structs.h" + +#ifndef NO_ASM +# if defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5T__) +# define EMBEDDED_ARM 4 +# define EMBEDDED_ARMv4 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_5TE__) || defined (__ARM_ARCH_5TEJ__) +# define EMBEDDED_ARM 5 +# define EMBEDDED_ARMv5 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_6__) ||defined (__ARM_ARCH_6J__) || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) +# define EMBEDDED_ARM 6 +# define EMBEDDED_ARMv6 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_7A__) && defined (__ARM_NEON__) +# define EMBEDDED_ARM 7 +# define EMBEDDED_ARMv6 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_7A__) +# define EMBEDDED_ARM 6 +# define EMBEDDED_ARMv6 +# include "SKP_Silk_macros_arm.h" +# else +# include "SKP_Silk_macros.h" +# endif +#else +# define EMBEDDED_ARM 0 +# include "SKP_Silk_macros.h" +#endif + + + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +SKP_int SKP_Silk_resampler_init( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int32 Fs_Hz_in, /* I: Input sampling rate (Hz) */ + SKP_int32 Fs_Hz_out /* I: Output sampling rate (Hz) */ +); + + +/*! + * Clear the states of all resampling filters, without resetting sampling rate ratio + */ +SKP_int SKP_Silk_resampler_clear( + SKP_Silk_resampler_state_struct *S /* I/O: Resampler state */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +SKP_int SKP_Silk_resampler( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/*! + Upsample 2x, low quality + */ +void SKP_Silk_resampler_up2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void SKP_Silk_resampler_down2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ len ] */ + const SKP_int16 *in, /* I: Input signal [ floor(len/2) ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + + +/*! + * Downsample by a factor 2/3, low quality +*/ +void SKP_Silk_resampler_down2_3( + SKP_int32 *S, /* I/O: State vector [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ floor(2*inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/*! + * Downsample by a factor 3, low quality +*/ +void SKP_Silk_resampler_down3( + SKP_int32 *S, /* I/O: State vector [ 8 ] */ + SKP_int16 *out, /* O: Output signal [ floor(inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/*! + * second order ARMA filter + * can handle (slowly) varying coefficients + */ +void SKP_Silk_biquad( + const SKP_int16 *in, /* I: input signal */ + const SKP_int16 *B, /* I: MA coefficients, Q13 [3] */ + const SKP_int16 *A, /* I: AR coefficients, Q13 [2] */ + SKP_int32 *S, /* I/O: state vector [2] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length */ +); +/*! + * Second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void SKP_Silk_biquad_alt( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int32 *B_Q28, /* I: MA coefficients [3] */ + const SKP_int32 *A_Q28, /* I: AR coefficients [2] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len /* I: Signal length (must be even) */ +); + +/*! + * variable order MA filter. Prediction error filter implementation. Coeficients negated and starting with coef to x[n - 1] + */ +void SKP_Silk_MA_Prediction( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int32 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 order /* I: Filter order */ +); + +/*! + * 16th order AR filter for LPC synthesis, coefficients are in Q12 + */ +void SKP_Silk_LPC_synthesis_order16( + const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [16], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [16] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length, must be multiple of 16 */ +); + +/* variable order MA prediction error filter. */ +/* Inverse filter of SKP_Silk_LPC_synthesis_filter */ +void SKP_Silk_LPC_analysis_filter( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int16 *B, /* I: MA prediction coefficients, Q12 [order] */ + SKP_int16 *S, /* I/O: State vector [order] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len, /* I: Signal length */ + const SKP_int32 Order /* I: Filter order */ +); + +/* even order AR filter */ +void SKP_Silk_LPC_synthesis_filter( + const SKP_int16 *in, /* I: excitation signal */ + const SKP_int16 *A_Q12, /* I: AR coefficients [Order], between -8_Q0 and 8_Q0 */ + const SKP_int32 Gain_Q26, /* I: gain */ + SKP_int32 *S, /* I/O: state vector [Order] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len, /* I: signal length */ + const SKP_int Order /* I: filter order, must be even */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander( + SKP_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander_32( + SKP_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +SKP_int SKP_Silk_LPC_inverse_pred_gain( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int16 *A_Q12, /* I: Prediction coefficients, Q12 [order] */ + const SKP_int order /* I: Prediction order */ +); + +SKP_int SKP_Silk_LPC_inverse_pred_gain_Q24( /* O: Returns 1 if unstable, otherwise 0 */ + SKP_int32 *invGain_Q30, /* O: Inverse prediction gain, Q30 energy domain */ + const SKP_int32 *A_Q24, /* I: Prediction coefficients, Q24 [order] */ + const SKP_int order /* I: Prediction order */ +); + +/* split signal in two decimated bands using first-order allpass filters */ +void SKP_Silk_ana_filt_bank_1( + const SKP_int16 *in, /* I: Input signal [N] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *outL, /* O: Low band [N/2] */ + SKP_int16 *outH, /* O: High band [N/2] */ + SKP_int32 *scratch, /* I: Scratch memory [3*N/2] */ + const SKP_int32 N /* I: Number of input samples */ +); + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (very close inverse of approx 2^() below) */ +/* Convert input to a log scale */ +SKP_int32 SKP_Silk_lin2log(const SKP_int32 inLin); /* I: Input in linear scale */ + +/* Approximation of a sigmoid function */ +SKP_int SKP_Silk_sigm_Q15(SKP_int in_Q5); + +/* approximation of 2^() (exact inverse of approx log2() above) */ +/* convert input to a linear scale */ +SKP_int32 SKP_Silk_log2lin(const SKP_int32 inLog_Q7); /* I: input on log scale */ + +/* Function that returns the maximum absolut value of the input vector */ +SKP_int16 SKP_Silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const SKP_int16 *vec, /* I Input vector [len] */ + const SKP_int32 len /* I Length of input vector */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void SKP_Silk_sum_sqr_shift( + SKP_int32 *energy, /* O Energy of x, after shifting to the right */ + SKP_int *shift, /* O Number of bits right shift applied to energy */ + const SKP_int16 *x, /* I Input vector */ + SKP_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* Uses SMLAWB(), requiring armv5E and higher. */ +SKP_int32 SKP_Silk_schur( /* O: Returns residual energy */ + SKP_int16 *rc_Q15, /* O: reflection coefficients [order] Q15 */ + const SKP_int32 *c, /* I: correlations [order+1] */ + const SKP_int32 order /* I: prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +SKP_int32 SKP_Silk_schur64( /* O: returns residual energy */ + SKP_int32 rc_Q16[], /* O: Reflection coefficients [order] Q16 */ + const SKP_int32 c[], /* I: Correlations [order+1] */ + SKP_int32 order /* I: Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a( + SKP_int32 *A_Q24, /* O: Prediction coefficients [order] Q24 */ + const SKP_int16 *rc_Q15, /* I: Reflection coefficients [order] Q15 */ + const SKP_int32 order /* I: Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a_Q16( + SKP_int32 *A_Q24, /* O: Prediction coefficients [order] Q24 */ + const SKP_int32 *rc_Q16, /* I: Reflection coefficients [order] Q16 */ + const SKP_int32 order /* I: Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +void SKP_Silk_apply_sine_window( + SKP_int16 px_win[], /* O Pointer to windowed signal */ + const SKP_int16 px[], /* I Pointer to input signal */ + const SKP_int win_type, /* I Selects a window type */ + const SKP_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void SKP_Silk_autocorr( + SKP_int32 *results, /* O Result (length correlationCount) */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *inputData, /* I Input data to correlate */ + const SKP_int inputDataSize, /* I Length of input */ + const SKP_int correlationCount /* I Number of correlation taps to compute */ +); + +/* Pitch estimator */ +#define SKP_Silk_PITCH_EST_MIN_COMPLEX 0 +#define SKP_Silk_PITCH_EST_MID_COMPLEX 1 +#define SKP_Silk_PITCH_EST_MAX_COMPLEX 2 + +void SKP_Silk_decode_pitch( + SKP_int lagIndex, /* I */ + SKP_int contourIndex, /* O */ + SKP_int pitch_lags[], /* O 4 pitch values */ + SKP_int Fs_kHz /* I sampling frequency (kHz) */ +); + +SKP_int SKP_Silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const SKP_int16 *signal, /* I Signal of length PITCH_EST_FRAME_LENGTH_MS*Fs_kHz */ + SKP_int *pitch_out, /* O 4 pitch lag values */ + SKP_int *lagIndex, /* O Lag Index */ + SKP_int *contourIndex, /* O Pitch contour Index */ + SKP_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + SKP_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const SKP_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const SKP_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const SKP_int Fs_kHz, /* I Sample frequency (kHz) */ + const SKP_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const SKP_int forLJC /* I 1 if this function is called from LJC code, 0 otherwise. */ +); + +/* parameter defining the size and accuracy of the piecewise linear */ +/* cosine approximatin table. */ + +#define LSF_COS_TAB_SZ_FIX 128 +/* rom table with cosine values */ +extern const SKP_int SKP_Silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void SKP_Silk_A2NLSF( + SKP_int *NLSF, /* O Normalized Line Spectral Frequencies, Q15 (0 - (2^15-1)), [d] */ + SKP_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const SKP_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void SKP_Silk_NLSF2A( + SKP_int16 *a, /* o monic whitening filter coefficients in Q12, [d] */ + const SKP_int *NLSF, /* i normalized line spectral frequencies in Q15, [d] */ + const SKP_int d /* i filter order (should be even) */ +); + +void SKP_Silk_insertion_sort_increasing( + SKP_int32 *a, /* I/O Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +); + +void SKP_Silk_insertion_sort_decreasing_int16( + SKP_int16 *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted positions */ +); + +void SKP_Silk_insertion_sort_increasing_all_values( + SKP_int *a, /* I/O: Unsorted / Sorted vector */ + const SKP_int L /* I: Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void SKP_Silk_NLSF_stabilize( + SKP_int *NLSF_Q15, /* I/O: Unstable/stabilized normalized LSF vector in Q15 [L] */ + const SKP_int *NDeltaMin_Q15, /* I: Normalized delta min vector in Q15, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const SKP_int L /* I: Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void SKP_Silk_NLSF_VQ_weights_laroia( + SKP_int *pNLSFW_Q6, /* O: Pointer to input vector weights [D x 1] */ + const SKP_int *pNLSF_Q15, /* I: Pointer to input vector [D x 1] */ + const SKP_int D /* I: Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void SKP_Silk_burg_modified( + SKP_int32 *res_nrg, /* O residual energy */ + SKP_int *res_nrgQ, /* O residual energy Q value */ + SKP_int32 A_Q16[], /* O prediction coefficients (length order) */ + const SKP_int16 x[], /* I input signal, length: nb_subfr * ( D + subfr_length ) */ + const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ + const SKP_int nb_subfr, /* I number of subframes stacked in x */ + const SKP_int32 WhiteNoiseFrac_Q32, /* I fraction added to zero-lag autocorrelation */ + const SKP_int D /* I order */ +); + +/* Copy and multiply a vector by a constant */ +void SKP_Silk_scale_copy_vector16( + SKP_int16 *data_out, + const SKP_int16 *data_in, + SKP_int32 gain_Q16, /* I: gain in Q16 */ + const SKP_int dataSize /* I: length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void SKP_Silk_scale_vector32_Q26_lshift_18( + SKP_int32 *data1, /* I/O: Q0/Q18 */ + SKP_int32 gain_Q26, /* I: Q26 */ + SKP_int dataSize /* I: length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum(inVec1[i]*inVec2[i]) */ +/* inVec1 and inVec2 should be increasing ordered, and starting address should be 4 byte aligned. (a factor of 4)*/ +SKP_int32 SKP_Silk_inner_prod_aligned( + const SKP_int16* const inVec1, /* I input vector 1 */ + const SKP_int16* const inVec2, /* I input vector 2 */ + const SKP_int len /* I vector lengths */ +); + +SKP_int64 SKP_Silk_inner_prod16_aligned_64( + const SKP_int16 *inVec1, /* I input vector 1 */ + const SKP_int16 *inVec2, /* I input vector 2 */ + const SKP_int len /* I vector lengths */ +); +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expressions below and + compile them into 'ror' instructions if available. No need for inline ASM! */ +#if defined(EMBEDDED_MIPS) +/* For MIPS (and most likely for ARM! and >=i486) we don't have to handle + negative rot's as only 5 bits of rot are encoded into ROR instructions. */ +SKP_INLINE SKP_int32 SKP_ROR32(SKP_int32 a32, SKP_int rot) +{ + SKP_uint32 _x = (SKP_uint32) a32; + SKP_uint32 _r = (SKP_uint32) rot; + return (SKP_int32) ((_x << (32 - _r)) | (_x >> _r)); +} +#else +/* PPC must use this generic implementation. */ +SKP_INLINE SKP_int32 SKP_ROR32( SKP_int32 a32, SKP_int rot ) +{ + SKP_uint32 x = (SKP_uint32) a32; + SKP_uint32 r = (SKP_uint32) rot; + SKP_uint32 m = (SKP_uint32) -rot; + if(rot <= 0) + return (SKP_int32) ((x << m) | (x >> (32 - m))); + else + return (SKP_int32) ((x << (32 - r)) | (x >> r)); +} +#endif + +/* Allocate SKP_int16 alligned to 4-byte memory address */ +#if EMBEDDED_ARM +#if defined(_WIN32) && defined(_M_ARM) +#define SKP_DWORD_ALIGN __declspec(align(4)) +#else +#define SKP_DWORD_ALIGN __attribute__((aligned(4))) +#endif +#else +#define SKP_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define SKP_memcpy(a, b, c) memcpy((a), (b), (c)) /* Dest, Src, ByteCount */ +#define SKP_memset(a, b, c) memset((a), (b), (c)) /* Dest, value, ByteCount */ +#define SKP_memmove(a, b, c) memmove((a), (b), (c)) /* Dest, Src, ByteCount */ +/* fixed point macros */ + +// (a32 * b32) output have to be 32bit int +#define SKP_MUL(a32, b32) ((a32) * (b32)) + +// (a32 * b32) output have to be 32bit uint +#define SKP_MUL_uint(a32, b32) SKP_MUL(a32, b32) + +// a32 + (b32 * c32) output have to be 32bit int +#define SKP_MLA(a32, b32, c32) SKP_ADD32((a32),((b32) * (c32))) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define SKP_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define SKP_SMLATT(a32, b32, c32) SKP_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define SKP_SMLALBB(a64, b16, c16) SKP_ADD64((a64),(SKP_int64)((SKP_int32)(b16) * (SKP_int32)(c16))) + +// (a32 * b32) +#define SKP_SMULL(a32, b32) ((SKP_int64)(a32) * /*(SKP_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define SKP_ADD32_ovflw(a, b) ((SKP_int32)((SKP_uint32)(a) + (SKP_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define SKP_SUB32_ovflw(a, b) ((SKP_int32)((SKP_uint32)(a) - (SKP_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define SKP_MLA_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), (SKP_uint32)(b32) * (SKP_uint32)(c32)) +#ifndef SKP_SMLABB_ovflw + #define SKP_SMLABB_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULBB((b32),(c32))) +#endif +#define SKP_SMLATT_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULTT((b32),(c32))) +#define SKP_SMLAWB_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULWB((b32),(c32))) +#define SKP_SMLAWT_ovflw(a32, b32, c32) SKP_ADD32_ovflw((a32), SKP_SMULWT((b32),(c32))) +#define SKP_DIV32_16(a32, b16) ((SKP_int32)((a32) / (b16))) +#define SKP_DIV32(a32, b32) ((SKP_int32)((a32) / (b32))) + +#define SKP_ADD32(a, b) ((a) + (b)) +#define SKP_ADD64(a, b) ((a) + (b)) + +#define SKP_SUB32(a, b) ((a) - (b)) + +#define SKP_SAT16(a) ((a) > SKP_int16_MAX ? SKP_int16_MAX : \ + ((a) < SKP_int16_MIN ? SKP_int16_MIN : (a))) +#define SKP_SAT32(a) ((a) > SKP_int32_MAX ? SKP_int32_MAX : \ + ((a) < SKP_int32_MIN ? SKP_int32_MIN : (a))) + +#define SKP_CHECK_FIT16(a) (a) +#define SKP_CHECK_FIT32(a) (a) + +#define SKP_ADD_SAT16(a, b) (SKP_int16)SKP_SAT16( SKP_ADD32( (SKP_int32)(a), (b) ) ) + +/* Add with saturation for positive input values */ +#define SKP_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? SKP_int32_MAX : ((a)+(b))) + +#define SKP_LSHIFT32(a, shift) ((a)<<(shift)) // shift >= 0, shift < 32 +#define SKP_LSHIFT64(a, shift) ((a)<<(shift)) // shift >= 0, shift < 64 +#define SKP_LSHIFT(a, shift) SKP_LSHIFT32(a, shift) // shift >= 0, shift < 32 + +#define SKP_RSHIFT32(a, shift) ((a)>>(shift)) // shift >= 0, shift < 32 +#define SKP_RSHIFT64(a, shift) ((a)>>(shift)) // shift >= 0, shift < 64 +#define SKP_RSHIFT(a, shift) SKP_RSHIFT32(a, shift) // shift >= 0, shift < 32 + +/* saturates before shifting */ +#define SKP_LSHIFT_SAT32(a, shift) (SKP_LSHIFT32( SKP_LIMIT_32( (a), SKP_RSHIFT32( SKP_int32_MIN, (shift) ), \ + SKP_RSHIFT32( SKP_int32_MAX, (shift) ) ), (shift) )) + +#define SKP_LSHIFT_ovflw(a, shift) ((a)<<(shift)) // shift >= 0, allowed to overflow +#define SKP_LSHIFT_uint(a, shift) ((a)<<(shift)) // shift >= 0 +#define SKP_RSHIFT_uint(a, shift) ((a)>>(shift)) // shift >= 0 + +#define SKP_ADD_LSHIFT(a, b, shift) ((a) + SKP_LSHIFT((b), (shift))) // shift >= 0 +#define SKP_ADD_LSHIFT32(a, b, shift) SKP_ADD32((a), SKP_LSHIFT32((b), (shift))) // shift >= 0 +#define SKP_ADD_RSHIFT(a, b, shift) ((a) + SKP_RSHIFT((b), (shift))) // shift >= 0 +#define SKP_ADD_RSHIFT32(a, b, shift) SKP_ADD32((a), SKP_RSHIFT32((b), (shift))) // shift >= 0 +#define SKP_ADD_RSHIFT_uint(a, b, shift) ((a) + SKP_RSHIFT_uint((b), (shift))) // shift >= 0 +#define SKP_SUB_LSHIFT32(a, b, shift) SKP_SUB32((a), SKP_LSHIFT32((b), (shift))) // shift >= 0 +#define SKP_SUB_RSHIFT32(a, b, shift) SKP_SUB32((a), SKP_RSHIFT32((b), (shift))) // shift >= 0 + +/* Requires that shift > 0 */ +#define SKP_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define SKP_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define SKP_NSHIFT_MUL_32_32(a, b) ( -(31- (32-SKP_Silk_CLZ32(SKP_abs(a)) + (32-SKP_Silk_CLZ32(SKP_abs(b))))) ) + +#define SKP_min(a, b) (((a) < (b)) ? (a) : (b)) +#define SKP_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SKP_FIX_CONST( C, Q ) ((SKP_int32)((C) * ((SKP_int64)1 << (Q)) + 0.5)) + +/* SKP_min() versions with typecast in the function call */ +SKP_INLINE SKP_int SKP_min_int(SKP_int a, SKP_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +SKP_INLINE SKP_int32 SKP_min_32(SKP_int32 a, SKP_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* SKP_min() versions with typecast in the function call */ +SKP_INLINE SKP_int SKP_max_int(SKP_int a, SKP_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +SKP_INLINE SKP_int16 SKP_max_16(SKP_int16 a, SKP_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +SKP_INLINE SKP_int32 SKP_max_32(SKP_int32 a, SKP_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define SKP_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define SKP_LIMIT_int SKP_LIMIT +#define SKP_LIMIT_32 SKP_LIMIT + +//#define SKP_non_neg(a) ((a) & ((-(a)) >> (8 * sizeof(a) - 1))) /* doesn't seem faster than SKP_max(0, a); + +#define SKP_abs(a) (((a) > 0) ? (a) : -(a)) // Be careful, SKP_abs returns wrong when input equals to SKP_intXX_MIN +#define SKP_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. Do not just mask off */ +/* the lowest bits. */ +#define SKP_RAND(seed) (SKP_MLA_ovflw(907633515, (seed), 196314165)) + +// Add some multiplication functions that can be easily mapped to ARM. + +// SKP_SMMUL: Signed top word multiply. +// ARMv6 2 instruction cycles. +// ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM) +//#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT(SKP_SMLAL(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)), 16) +// the following seems faster on x86 +//#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) + +#include "SKP_Silk_Inlines.h" + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_VAD.c b/pkg/silk/csilk/SKP_Silk_VAD.c new file mode 100644 index 0000000..35a5a9d --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_VAD.c @@ -0,0 +1,320 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + * File Name: SKP_Silk_VAD.c + * Description: Silk VAD. + */ + +#include +#include "SKP_Silk_main.h" + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +SKP_int SKP_Silk_VAD_Init( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + SKP_int b, ret = 0; + + /* reset state memory */ + SKP_memset( psSilk_VAD, 0, sizeof( SKP_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 ] = SKP_max_32( SKP_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = SKP_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = SKP_DIV32( SKP_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 */ +const static SKP_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +SKP_int SKP_Silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD, /* I/O Silk VAD state */ + SKP_int *pSA_Q8, /* O Speech activity level in Q8 */ + SKP_int *pSNR_dB_Q7, /* O SNR for current frame in Q7 */ + SKP_int pQuality_Q15[ VAD_N_BANDS ], /* O Smoothed SNR for each band */ + SKP_int *pTilt_Q15, /* O current frame's frequency tilt */ + const SKP_int16 pIn[], /* I PCM input [framelength] */ + const SKP_int framelength /* I Input frame length */ +) +{ + SKP_int SA_Q15, input_tilt; + SKP_int32 scratch[ 3 * MAX_FRAME_LENGTH / 2 ]; + SKP_int decimated_framelength, dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + SKP_int32 sumSquared, smooth_coef_Q16; + SKP_int16 HPstateTmp; + + SKP_int16 X[ VAD_N_BANDS ][ MAX_FRAME_LENGTH / 2 ]; + SKP_int32 Xnrg[ VAD_N_BANDS ]; + SKP_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + SKP_int32 speech_nrg, x_tmp; + SKP_int ret = 0; + + /* Safety checks */ + SKP_assert( VAD_N_BANDS == 4 ); + SKP_assert( MAX_FRAME_LENGTH >= framelength ); + SKP_assert( framelength <= 512 ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + SKP_Silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], &X[ 0 ][ 0 ], &X[ 3 ][ 0 ], &scratch[ 0 ], framelength ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + SKP_Silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState1[ 0 ], &X[ 0 ][ 0 ], &X[ 2 ][ 0 ], &scratch[ 0 ], SKP_RSHIFT( framelength, 1 ) ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + SKP_Silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState2[ 0 ], &X[ 0 ][ 0 ], &X[ 1 ][ 0 ], &scratch[ 0 ], SKP_RSHIFT( framelength, 2 ) ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + decimated_framelength = SKP_RSHIFT( framelength, 3 ); + X[ 0 ][ decimated_framelength - 1 ] = SKP_RSHIFT( X[ 0 ][ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ 0 ][ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ 0 ][ i - 1 ] = SKP_RSHIFT( X[ 0 ][ i - 1 ], 1 ); + X[ 0 ][ i ] -= X[ 0 ][ i - 1 ]; + } + X[ 0 ][ 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 = SKP_RSHIFT( framelength, SKP_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = SKP_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 * ( SKP_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = SKP_RSHIFT( X[ b ][ i + dec_subframe_offset ], 3 ); + sumSquared = SKP_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + SKP_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = SKP_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = SKP_ADD_POS_SAT32( Xnrg[ b ], SKP_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + SKP_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 ] = SKP_DIV32( SKP_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = SKP_DIV32( Xnrg[ b ], SKP_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = SKP_Silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = SKP_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( 1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = SKP_SMULWB( SKP_LSHIFT( SKP_Silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = SKP_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = SKP_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + *pSNR_dB_Q7 = ( SKP_int16 )( 3 * SKP_Silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = SKP_Silk_sigm_Q15( SKP_SMULWB( VAD_SNR_FACTOR_Q16, *pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + *pTilt_Q15 = SKP_LSHIFT( SKP_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 ) * SKP_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = SKP_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + /* square-root */ + speech_nrg = SKP_Silk_SQRT_APPROX( SKP_LSHIFT( speech_nrg, 15 ) ); + SA_Q15 = SKP_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 to *pSA_Q8 */ + *pSA_Q8 = SKP_min_int( SKP_RSHIFT( SA_Q15, 7 ), SKP_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = SKP_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, SKP_SMULWB( SA_Q15, SA_Q15 ) ); + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = SKP_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 * ( SKP_Silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + pQuality_Q15[ b ] = SKP_Silk_sigm_Q15( SKP_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +void SKP_Silk_VAD_GetNoiseLevels( + const SKP_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + SKP_int k; + SKP_int32 nl, nrg, inv_nrg; + SKP_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = SKP_DIV32_16( SKP_int16_MAX, SKP_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + } 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 ]; + SKP_assert( nl >= 0 ); + + /* Add bias */ + nrg = SKP_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + SKP_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = SKP_DIV32( SKP_int32_MAX, nrg ); + SKP_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > SKP_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = SKP_SMULWB( SKP_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = SKP_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = SKP_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + SKP_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = SKP_DIV32( SKP_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + SKP_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = SKP_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } + + /* Increment frame counter */ + psSilk_VAD->counter++; +} diff --git a/pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c b/pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c new file mode 100644 index 0000000..74a2653 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c @@ -0,0 +1,159 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Entropy constrained MATRIX-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void SKP_Silk_VQ_WMat_EC_FIX( + SKP_int *ind, /* O index of best codebook vector */ + SKP_int32 *rate_dist_Q14, /* O best weighted quantization error + mu * rate*/ + const SKP_int16 *in_Q14, /* I input vector to be quantized */ + const SKP_int32 *W_Q18, /* I weighting matrix */ + const SKP_int16 *cb_Q14, /* I codebook */ + const SKP_int16 *cl_Q6, /* I code length for each codebook vector */ + const SKP_int mu_Q8, /* I tradeoff between weighted error and rate */ + SKP_int L /* I number of vectors in codebook */ +) +{ + SKP_int k; + const SKP_int16 *cb_row_Q14; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 sum1_Q14, sum2_Q16, diff_Q14_01, diff_Q14_23, diff_Q14_4; +#else + SKP_int16 diff_Q14[ 5 ]; + SKP_int32 sum1_Q14, sum2_Q16; +#endif + + /* Loop over codebook */ + *rate_dist_Q14 = SKP_int32_MAX; + cb_row_Q14 = cb_Q14; + for( k = 0; k < L; k++ ) { +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* Pack pairs of int16 values per int32 */ + diff_Q14_01 = ( SKP_uint16 )( in_Q14[ 0 ] - cb_row_Q14[ 0 ] ) | SKP_LSHIFT( ( SKP_int32 )in_Q14[ 1 ] - cb_row_Q14[ 1 ], 16 ); + diff_Q14_23 = ( SKP_uint16 )( in_Q14[ 2 ] - cb_row_Q14[ 2 ] ) | SKP_LSHIFT( ( SKP_int32 )in_Q14[ 3 ] - cb_row_Q14[ 3 ], 16 ); + diff_Q14_4 = in_Q14[ 4 ] - cb_row_Q14[ 4 ]; +#else + diff_Q14[ 0 ] = in_Q14[ 0 ] - cb_row_Q14[ 0 ]; + diff_Q14[ 1 ] = in_Q14[ 1 ] - cb_row_Q14[ 1 ]; + diff_Q14[ 2 ] = in_Q14[ 2 ] - cb_row_Q14[ 2 ]; + diff_Q14[ 3 ] = in_Q14[ 3 ] - cb_row_Q14[ 3 ]; + diff_Q14[ 4 ] = in_Q14[ 4 ] - cb_row_Q14[ 4 ]; +#endif + + /* Weighted rate */ + sum1_Q14 = SKP_SMULBB( mu_Q8, cl_Q6[ k ] ); + + SKP_assert( sum1_Q14 >= 0 ); + +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* Add weighted quantization error, assuming W_Q18 is symmetric */ + /* NOTE: the code below loads two int16 values as one int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + /* first row of W_Q18 */ + sum2_Q16 = SKP_SMULWT( W_Q18[ 1 ], diff_Q14_01 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 3 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14_01 ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14_01 ); + + /* second row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 7 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 8 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 6 ], diff_Q14_01 ); + sum1_Q14 = SKP_SMLAWT( sum1_Q14, sum2_Q16, diff_Q14_01 ); + + /* third row of W_Q18 */ + sum2_Q16 = SKP_SMULWT( W_Q18[ 13 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14_23 ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14_23 ); + + /* fourth row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 19 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 18 ], diff_Q14_23 ); + sum1_Q14 = SKP_SMLAWT( sum1_Q14, sum2_Q16, diff_Q14_23 ); + + /* last row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 24 ], diff_Q14_4 ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14_4 ); +#else + /* first row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); +#endif + + SKP_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = k; + } + + /* Go to next cbk vector */ + cb_row_Q14 += LTP_ORDER; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c b/pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c new file mode 100644 index 0000000..206f3b5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c @@ -0,0 +1,82 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_ana_filt_bank_1.c * + * * + * Split signal into two decimated bands using first-order allpass filters * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +#if EMBEDDED_ARM<5 +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +// old +static SKP_int16 A_fb1_20[ 1 ] = { 5394 << 1 }; +static SKP_int16 A_fb1_21[ 1 ] = { (SKP_int16) (20623 << 1) }; /* wrap-around to negative number is intentional */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void SKP_Silk_ana_filt_bank_1( + const SKP_int16 *in, /* I: Input signal [N] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *outL, /* O: Low band [N/2] */ + SKP_int16 *outH, /* O: High band [N/2] */ + SKP_int32 *scratch, /* I: Scratch memory [3*N/2] */ // todo: remove - no longer used + const SKP_int32 N /* I: Number of input samples */ +) +{ + SKP_int k, N2 = SKP_RSHIFT( N, 1 ); + SKP_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 = SKP_LSHIFT( (SKP_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMLAWB( Y, Y, A_fb1_21[ 0 ] ); + out_1 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMULWB( Y, A_fb1_20[ 0 ] ); + out_2 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( SKP_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SUB32( out_2, out_1 ), 11 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_apply_sine_window.c b/pkg/silk/csilk/SKP_Silk_apply_sine_window.c new file mode 100644 index 0000000..b7706d7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_apply_sine_window.c @@ -0,0 +1,120 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_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 SKP_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, +}; + +//#if EMBEDDED_ARM<6 +void SKP_Silk_apply_sine_window( + SKP_int16 px_win[], /* O Pointer to windowed signal */ + const SKP_int16 px[], /* I Pointer to input signal */ + const SKP_int win_type, /* I Selects a window type */ + const SKP_int length /* I Window length, multiple of 4 */ +) +{ + SKP_int k, f_Q16, c_Q16; + SKP_int32 S0_Q16, S1_Q16; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 px32; +#endif + SKP_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + SKP_assert( length >= 16 && length <= 120 ); + SKP_assert( ( length & 3 ) == 0 ); + + /* Input pointer must be 4-byte aligned */ + SKP_assert( ( ( SKP_int64 )( ( SKP_int8* )px - ( SKP_int8* )0 ) & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + SKP_assert( k >= 0 && k <= 26 ); + f_Q16 = (SKP_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = SKP_SMULWB( f_Q16, -f_Q16 ); + SKP_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + SKP_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( 1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( 1 << 16 ) + SKP_RSHIFT( c_Q16, 1 ) + SKP_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 */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + for( k = 0; k < length; k += 4 ) { + px32 = *( (SKP_int32 *)&px[ k ] ); /* load two values at once */ + px_win[ k ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px32 ); + px_win[ k + 1 ] = (SKP_int16)SKP_SMULWT( S1_Q16, px32 ); + S0_Q16 = SKP_SMULWB( S1_Q16, c_Q16 ) + SKP_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = SKP_min( S0_Q16, ( 1 << 16 ) ); + + px32 = *( (SKP_int32 *)&px[k + 2] ); /* load two values at once */ + px_win[ k + 2 ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px32 ); + px_win[ k + 3 ] = (SKP_int16)SKP_SMULWT( S0_Q16, px32 ); + S1_Q16 = SKP_SMULWB( S0_Q16, c_Q16 ) + SKP_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = SKP_min( S1_Q16, ( 1 << 16 ) ); + } +#else + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (SKP_int16)SKP_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = SKP_SMULWB( S1_Q16, c_Q16 ) + SKP_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = SKP_min( S0_Q16, ( 1 << 16 ) ); + + px_win[ k + 2 ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (SKP_int16)SKP_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = SKP_SMULWB( S0_Q16, c_Q16 ) + SKP_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = SKP_min( S1_Q16, ( 1 << 16 ) ); + } +#endif +} +//#endif diff --git a/pkg/silk/csilk/SKP_Silk_array_maxabs.c b/pkg/silk/csilk/SKP_Silk_array_maxabs.c new file mode 100644 index 0000000..0d6be63 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_array_maxabs.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_int16_array_maxabs.c * + * * + * Function that returns the maximum absolut value of * + * the input vector * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Function that returns the maximum absolut value of the input vector */ +#if (EMBEDDED_ARM<4) +SKP_int16 SKP_Silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const SKP_int16 *vec, /* I Input vector [len] */ + const SKP_int32 len /* I Length of input vector */ +) +{ + SKP_int32 max = 0, i, lvl = 0, ind; + if( len == 0 ) return 0; + + ind = len - 1; + max = SKP_SMULBB( vec[ ind ], vec[ ind ] ); + for( i = len - 2; i >= 0; i-- ) { + lvl = SKP_SMULBB( vec[ i ], vec[ i ] ); + if( lvl > max ) { + max = lvl; + ind = i; + } + } + + /* Do not return 32768, as it will not fit in an int16 so may lead to problems later on */ + if( max >= 1073676289 ) { // (2^15-1)^2 = 1073676289 + return( SKP_int16_MAX ); + } else { + if( vec[ ind ] < 0 ) { + return( -vec[ ind ] ); + } else { + return( vec[ ind ] ); + } + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_autocorr.c b/pkg/silk/csilk/SKP_Silk_autocorr.c new file mode 100644 index 0000000..39ca5ab --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_autocorr.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_autocorr.c * + * * + * Calculates the autocorrelation * + * The result has 29 non-zero bits for the first correlation, to leave * + * some room for adding white noise fractions etc. * + * * + * Copyright 2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Compute autocorrelation */ +void SKP_Silk_autocorr( + SKP_int32 *results, /* O Result (length correlationCount) */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *inputData, /* I Input data to correlate */ + const SKP_int inputDataSize, /* I Length of input */ + const SKP_int correlationCount /* I Number of correlation taps to compute */ +) +{ + SKP_int i, lz, nRightShifts, corrCount; + SKP_int64 corr64; + + corrCount = SKP_min_int( inputDataSize, correlationCount ); + + /* compute energy (zero-lag correlation) */ + corr64 = SKP_Silk_inner_prod16_aligned_64( inputData, inputData, inputDataSize ); + + /* deal with all-zero input data */ + corr64 += 1; + + /* number of leading zeros */ + lz = SKP_Silk_CLZ64( corr64 ); + + /* scaling: number of right shifts applied to correlations */ + nRightShifts = 35 - lz; + *scale = nRightShifts; + + if( nRightShifts <= 0 ) { + results[ 0 ] = SKP_LSHIFT( (SKP_int32)SKP_CHECK_FIT32( corr64 ), -nRightShifts ); + + /* compute remaining correlations based on int32 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = SKP_LSHIFT( SKP_Silk_inner_prod_aligned( inputData, inputData + i, inputDataSize - i ), -nRightShifts ); + } + } else { + results[ 0 ] = (SKP_int32)SKP_CHECK_FIT32( SKP_RSHIFT64( corr64, nRightShifts ) ); + + /* compute remaining correlations based on int64 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = (SKP_int32)SKP_CHECK_FIT32( SKP_RSHIFT64( SKP_Silk_inner_prod16_aligned_64( inputData, inputData + i, inputDataSize - i ), nRightShifts ) ); + } + } +} diff --git a/pkg/silk/csilk/SKP_Silk_biquad.c b/pkg/silk/csilk/SKP_Silk_biquad.c new file mode 100644 index 0000000..f98de55 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_biquad.c @@ -0,0 +1,72 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_biquad.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Second order ARMA filter */ +/* Can handle slowly varying filter coefficients */ +void SKP_Silk_biquad( + const SKP_int16 *in, /* I: input signal */ + const SKP_int16 *B, /* I: MA coefficients, Q13 [3] */ + const SKP_int16 *A, /* I: AR coefficients, Q13 [2] */ + SKP_int32 *S, /* I/O: state vector [2] */ + SKP_int16 *out, /* O: output signal */ + const SKP_int32 len /* I: signal length */ +) +{ + SKP_int k, in16; + SKP_int32 A0_neg, A1_neg, S0, S1, out32, tmp32; + + S0 = S[ 0 ]; + S1 = S[ 1 ]; + A0_neg = -A[ 0 ]; + A1_neg = -A[ 1 ]; + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q13 */ + in16 = in[ k ]; + out32 = SKP_SMLABB( S0, in16, B[ 0 ] ); + + S0 = SKP_SMLABB( S1, in16, B[ 1 ] ); + S0 += SKP_LSHIFT( SKP_SMULWB( out32, A0_neg ), 3 ); + + S1 = SKP_LSHIFT( SKP_SMULWB( out32, A1_neg ), 3 ); + S1 = SKP_SMLABB( S1, in16, B[ 2 ] ); + tmp32 = SKP_RSHIFT_ROUND( out32, 13 ) + 1; + out[ k ] = (SKP_int16)SKP_SAT16( tmp32 ); + } + S[ 0 ] = S0; + S[ 1 ] = S1; +} diff --git a/pkg/silk/csilk/SKP_Silk_biquad_alt.c b/pkg/silk/csilk/SKP_Silk_biquad_alt.c new file mode 100644 index 0000000..90c27ac --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_biquad_alt.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ +#include "SKP_Silk_SigProc_FIX.h" + + +/* Second order ARMA filter, alternative implementation */ +void SKP_Silk_biquad_alt( + const SKP_int16 *in, /* I: Input signal */ + const SKP_int32 *B_Q28, /* I: MA coefficients [3] */ + const SKP_int32 *A_Q28, /* I: AR coefficients [2] */ + SKP_int32 *S, /* I/O: State vector [2] */ + SKP_int16 *out, /* O: Output signal */ + const SKP_int32 len /* I: Signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + SKP_int k; + SKP_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 = SKP_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = SKP_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k ]; + out32_Q14 = SKP_LSHIFT( SKP_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + SKP_RSHIFT_ROUND( SKP_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = SKP_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = SKP_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = SKP_RSHIFT_ROUND( SKP_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = SKP_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = SKP_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_burg_modified.c b/pkg/silk/csilk/SKP_Silk_burg_modified.c new file mode 100644 index 0000000..8708b8b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_burg_modified.c @@ -0,0 +1,229 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_burg_modified.c * + * * + * Calculates the reflection coefficients from the input vector * + * Input vector contains nb_subfr sub vectors of length L_sub + D * + * * + * Copyright 2009 (c), Skype Limited * + * Date: 100105 * + */ + +#include "SKP_Silk_SigProc_FIX.h" + +#define MAX_FRAME_SIZE 544 // subfr_length * nb_subfr = ( 0.005 * 24000 + 16 ) * 4 = 544 +#define MAX_NB_SUBFR 4 + +#undef QA +#define QA 25 +#define N_BITS_HEAD_ROOM 2 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void SKP_Silk_burg_modified( + SKP_int32 *res_nrg, /* O residual energy */ + SKP_int *res_nrg_Q, /* O residual energy Q value */ + SKP_int32 A_Q16[], /* O prediction coefficients (length order) */ + const SKP_int16 x[], /* I input signal, length: nb_subfr * ( D + subfr_length ) */ + const SKP_int subfr_length, /* I input signal subframe length (including D preceeding samples) */ + const SKP_int nb_subfr, /* I number of subframes stacked in x */ + const SKP_int32 WhiteNoiseFrac_Q32, /* I fraction added to zero-lag autocorrelation */ + const SKP_int D /* I order */ +) +{ + SKP_int k, n, s, lz, rshifts, rshifts_extra; + SKP_int32 C0, num, nrg, rc_Q31, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const SKP_int16 *x_ptr; + + SKP_int32 C_first_row[ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 C_last_row[ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 Af_QA[ SKP_Silk_MAX_ORDER_LPC ]; + + SKP_int32 CAf[ SKP_Silk_MAX_ORDER_LPC + 1 ]; + SKP_int32 CAb[ SKP_Silk_MAX_ORDER_LPC + 1 ]; + + SKP_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + SKP_assert( nb_subfr <= MAX_NB_SUBFR ); + + + /* Compute autocorrelations, added over subframes */ + SKP_Silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = SKP_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + SKP_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = SKP_Silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = SKP_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = SKP_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = SKP_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = SKP_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + SKP_memset( C_first_row, 0, SKP_Silk_MAX_ORDER_LPC * sizeof( SKP_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 ] += (SKP_int32)SKP_RSHIFT64( + SKP_Silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n ), rshifts ); + } + } + } else { + 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 ] += SKP_LSHIFT32( + SKP_Silk_inner_prod_aligned( x_ptr, x_ptr + n, subfr_length - n ), -rshifts ); + } + } + } + SKP_memcpy( C_last_row, C_first_row, SKP_Silk_MAX_ORDER_LPC * sizeof( SKP_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + SKP_SMMUL( WhiteNoiseFrac_Q32, C0 ) + 1; // Q(-rshifts) + + 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 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], 16 - rshifts ); // Q(16-rshifts) + x2 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); // Q(16-rshifts) + tmp1 = SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], QA - 16 ); // Q(QA-16) + tmp2 = SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); // Q(QA-16) + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = SKP_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); // Q( -rshifts ) + C_last_row[ k ] = SKP_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); // Q( -rshifts ) + Atmp_QA = Af_QA[ k ]; + tmp1 = SKP_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); // Q(QA-16) + tmp2 = SKP_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); // Q(QA-16) + } + tmp1 = SKP_LSHIFT32( -tmp1, 32 - QA - rshifts ); // Q(16-rshifts) + tmp2 = SKP_LSHIFT32( -tmp2, 32 - QA - rshifts ); // Q(16-rshifts) + for( k = 0; k <= n; k++ ) { + CAf[ k ] = SKP_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); // Q( -rshift ) + CAb[ k ] = SKP_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 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], -rshifts ); // Q( -rshifts ) + x2 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); // Q( -rshifts ) + tmp1 = SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], 17 ); // Q17 + tmp2 = SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], 17 ); // Q17 + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = SKP_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); // Q( -rshifts ) + C_last_row[ k ] = SKP_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); // Q( -rshifts ) + Atmp1 = SKP_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); // Q17 + tmp1 = SKP_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); // Q17 + tmp2 = SKP_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); // Q17 + } + tmp1 = -tmp1; // Q17 + tmp2 = -tmp2; // Q17 + for( k = 0; k <= n; k++ ) { + CAf[ k ] = SKP_SMLAWW( CAf[ k ], tmp1, + SKP_LSHIFT32( (SKP_int32)x_ptr[ n - k ], -rshifts - 1 ) ); // Q( -rshift ) + CAb[ k ] = SKP_SMLAWW( CAb[ k ], tmp2, + SKP_LSHIFT32( (SKP_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 = SKP_ADD32( CAb[ 0 ], CAf[ 0 ] ); // Q( 1-rshifts ) + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = SKP_Silk_CLZ32( SKP_abs( Atmp_QA ) ) - 1; + lz = SKP_min( 32 - QA, lz ); + Atmp1 = SKP_LSHIFT32( Atmp_QA, lz ); // Q( QA + lz ) + + tmp1 = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) + tmp2 = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) + num = SKP_ADD_LSHIFT32( num, SKP_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) + nrg = SKP_ADD_LSHIFT32( nrg, SKP_SMMUL( SKP_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 = SKP_ADD32( num, tmp2 ); // Q( -rshifts ) + num = SKP_LSHIFT32( -num, 1 ); // Q( 1-rshifts ) + + /* Calculate the next order reflection (parcor) coefficient */ + if( SKP_abs( num ) < nrg ) { + rc_Q31 = SKP_DIV32_varQ( num, nrg, 31 ); + } else { + /* Negative energy or ratio too high; set remaining coefficients to zero and exit loop */ + SKP_memset( &Af_QA[ n ], 0, ( D - n ) * sizeof( SKP_int32 ) ); + SKP_assert( 0 ); + break; + } + + /* 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 ] = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( tmp2, rc_Q31 ), 1 ); // QA + Af_QA[ n - k - 1 ] = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( tmp1, rc_Q31 ), 1 ); // QA + } + Af_QA[ n ] = SKP_RSHIFT32( rc_Q31, 31 - QA ); // QA + + /* 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 ] = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( tmp2, rc_Q31 ), 1 ); // Q( -rshifts ) + CAb[ n - k + 1 ] = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( tmp1, rc_Q31 ), 1 ); // Q( -rshifts ) + } + } + + /* Return residual energy */ + nrg = CAf[ 0 ]; // Q( -rshifts ) + tmp1 = 1 << 16; // Q16 + for( k = 0; k < D; k++ ) { + Atmp1 = SKP_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); // Q16 + nrg = SKP_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); // Q( -rshifts ) + tmp1 = SKP_SMLAWW( tmp1, Atmp1, Atmp1 ); // Q16 + A_Q16[ k ] = -Atmp1; + } + *res_nrg = SKP_SMLAWW( nrg, SKP_SMMUL( WhiteNoiseFrac_Q32, C0 ), -tmp1 ); // Q( -rshifts ) + *res_nrg_Q = -rshifts; +} diff --git a/pkg/silk/csilk/SKP_Silk_bwexpander.c b/pkg/silk/csilk/SKP_Silk_bwexpander.c new file mode 100644 index 0000000..6affb6b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_bwexpander.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander( + SKP_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + SKP_int i; + SKP_int32 chirp_minus_one_Q16; + + chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use SKP_SMULWB, instead of SKP_RSHIFT_ROUND( SKP_MUL() , 16 ), below. */ + /* Bias in SKP_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (SKP_int16)SKP_RSHIFT_ROUND( SKP_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += SKP_RSHIFT_ROUND( SKP_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (SKP_int16)SKP_RSHIFT_ROUND( SKP_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/pkg/silk/csilk/SKP_Silk_bwexpander_32.c b/pkg/silk/csilk/SKP_Silk_bwexpander_32.c new file mode 100644 index 0000000..0a83869 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_bwexpander_32.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void SKP_Silk_bwexpander_32( + SKP_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const SKP_int d, /* I Length of ar */ + SKP_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + SKP_int i; + SKP_int32 tmp_chirp_Q16; + + tmp_chirp_Q16 = chirp_Q16; + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = SKP_SMULWW( ar[ i ], tmp_chirp_Q16 ); + tmp_chirp_Q16 = SKP_SMULWW( chirp_Q16, tmp_chirp_Q16 ); + } + ar[ d - 1 ] = SKP_SMULWW( ar[ d - 1 ], tmp_chirp_Q16 ); +} diff --git a/pkg/silk/csilk/SKP_Silk_code_signs.c b/pkg/silk/csilk/SKP_Silk_code_signs.c new file mode 100644 index 0000000..3149f4a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_code_signs.c @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +//#define SKP_enc_map(a) ((a) > 0 ? 1 : 0) +//#define SKP_dec_map(a) ((a) > 0 ? 1 : -1) +/* shifting avoids if-statement */ +#define SKP_enc_map(a) ( SKP_RSHIFT( (a), 15 ) + 1 ) +#define SKP_dec_map(a) ( SKP_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void SKP_Silk_encode_signs( + SKP_Silk_range_coder_state *sRC, /* I/O Range coder state */ + const SKP_int8 q[], /* I Pulse signal */ + const SKP_int length, /* I Length of input */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate level index */ +) +{ + SKP_int i; + SKP_int inData; + SKP_uint16 cdf[ 3 ]; + + i = SKP_SMULBB( N_RATE_LEVELS - 1, SKP_LSHIFT( sigtype, 1 ) + QuantOffsetType ) + RateLevelIndex; + cdf[ 0 ] = 0; + cdf[ 1 ] = SKP_Silk_sign_CDF[ i ]; + cdf[ 2 ] = 65535; + + for( i = 0; i < length; i++ ) { + if( q[ i ] != 0 ) { + inData = SKP_enc_map( q[ i ] ); /* - = 0, + = 1 */ + SKP_Silk_range_encoder( sRC, inData, cdf ); + } + } +} + +/* Decodes signs of excitation */ +void SKP_Silk_decode_signs( + SKP_Silk_range_coder_state *sRC, /* I/O Range coder state */ + SKP_int q[], /* I/O pulse signal */ + const SKP_int length, /* I length of output */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate Level Index */ +) +{ + SKP_int i; + SKP_int data; + SKP_uint16 cdf[ 3 ]; + + i = SKP_SMULBB( N_RATE_LEVELS - 1, SKP_LSHIFT( sigtype, 1 ) + QuantOffsetType ) + RateLevelIndex; + cdf[ 0 ] = 0; + cdf[ 1 ] = SKP_Silk_sign_CDF[ i ]; + cdf[ 2 ] = 65535; + + for( i = 0; i < length; i++ ) { + if( q[ i ] > 0 ) { + SKP_Silk_range_decoder( &data, sRC, cdf, 1 ); + /* attach sign */ + /* implementation with shift, subtraction, multiplication */ + q[ i ] *= SKP_dec_map( data ); + } + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_common_pitch_est_defines.h b/pkg/silk/csilk/SKP_Silk_common_pitch_est_defines.h new file mode 100644 index 0000000..7ca23d3 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_common_pitch_est_defines.h @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROC_COMMON_PITCH_EST_DEFINES_H +#define SIGPROC_COMMON_PITCH_EST_DEFINES_H + +#include "SKP_Silk_SigProc_FIX.h" + +/************************************************************/ +/* Definitions For Fix pitch estimator */ +/************************************************************/ + +#define PITCH_EST_MAX_FS_KHZ 24 /* Maximum sampling frequency used */ + +#define PITCH_EST_FRAME_LENGTH_MS 40 /* 40 ms */ + +#define PITCH_EST_MAX_FRAME_LENGTH (PITCH_EST_FRAME_LENGTH_MS * PITCH_EST_MAX_FS_KHZ) +#define PITCH_EST_MAX_FRAME_LENGTH_ST_1 (PITCH_EST_MAX_FRAME_LENGTH >> 2) +#define PITCH_EST_MAX_FRAME_LENGTH_ST_2 (PITCH_EST_MAX_FRAME_LENGTH >> 1) +#define PITCH_EST_MAX_SF_FRAME_LENGTH (PITCH_EST_SUB_FRAME * PITCH_EST_MAX_FS_KHZ) + +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG (PITCH_EST_MAX_LAG_MS * PITCH_EST_MAX_FS_KHZ) +#define PITCH_EST_MIN_LAG (PITCH_EST_MIN_LAG_MS * PITCH_EST_MAX_FS_KHZ) + +#define PITCH_EST_NB_SUBFR 4 + +#define PITCH_EST_D_SRCH_LENGTH 24 + +#define PITCH_EST_MAX_DECIMATE_STATE_LENGTH 7 + +#define PITCH_EST_NB_STAGE3_LAGS 5 + +#define PITCH_EST_NB_CBKS_STAGE2 3 +#define PITCH_EST_NB_CBKS_STAGE2_EXT 11 + +#define PITCH_EST_CB_mn2 1 +#define PITCH_EST_CB_mx2 2 + +#define PITCH_EST_NB_CBKS_STAGE3_MAX 34 +#define PITCH_EST_NB_CBKS_STAGE3_MID 24 +#define PITCH_EST_NB_CBKS_STAGE3_MIN 16 + +extern const SKP_int16 SKP_Silk_CB_lags_stage2[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE2_EXT]; +extern const SKP_int16 SKP_Silk_CB_lags_stage3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX]; +extern const SKP_int16 SKP_Silk_Lag_range_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ] [ PITCH_EST_NB_SUBFR ][ 2 ]; +extern const SKP_int16 SKP_Silk_cbk_sizes_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ]; +extern const SKP_int16 SKP_Silk_cbk_offsets_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ]; + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_control.h b/pkg/silk/csilk/SKP_Silk_control.h new file mode 100644 index 0000000..ef0eac2 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_control.h @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_CONTROL_H +#define SKP_SILK_CONTROL_H + +#include "SKP_Silk_typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000 */ + SKP_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000/24000 */ + SKP_int32 maxInternalSampleRate; + + /* I: Number of samples per packet; must be equivalent of 20, 40, 60, 80 or 100 ms */ + SKP_int packetSize; + + /* I: Bitrate during active speech in bits/second; internally limited */ + SKP_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + SKP_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest; 1 is medium and 2 is highest complexity */ + SKP_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + SKP_int useInBandFEC; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + SKP_int useDTX; +} SKP_SILK_SDK_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000 */ + SKP_int32 API_sampleRate; + + /* O: Number of samples per frame */ + SKP_int frameSize; + + /* O: Frames per packet 1, 2, 3, 4, 5 */ + SKP_int framesPerPacket; + + /* O: Flag to indicate that the decoder has remaining payloads internally */ + SKP_int moreInternalDecoderFrames; + + /* O: Distance between main payload and redundant payload in packets */ + SKP_int inBandFECOffset; +} SKP_SILK_SDK_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_control_audio_bandwidth.c b/pkg/silk/csilk/SKP_Silk_control_audio_bandwidth.c new file mode 100644 index 0000000..e7bed0c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_control_audio_bandwidth.c @@ -0,0 +1,137 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Control internal sampling rate */ +SKP_int SKP_Silk_control_audio_bandwidth( + SKP_Silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + const SKP_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + SKP_int fs_kHz; + + fs_kHz = psEncC->fs_kHz; + if( fs_kHz == 0 ) { + /* Encoder has just been initialized */ + if( TargetRate_bps >= SWB2WB_BITRATE_BPS ) { + fs_kHz = 24; + } else if( TargetRate_bps >= WB2MB_BITRATE_BPS ) { + fs_kHz = 16; + } else if( TargetRate_bps >= MB2NB_BITRATE_BPS ) { + fs_kHz = 12; + } else { + fs_kHz = 8; + } + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_kHz = SKP_min( fs_kHz, SKP_DIV32_16( psEncC->API_fs_Hz, 1000 ) ); + fs_kHz = SKP_min( fs_kHz, psEncC->maxInternal_fs_kHz ); + } else if( SKP_SMULBB( fs_kHz, 1000 ) > psEncC->API_fs_Hz || fs_kHz > psEncC->maxInternal_fs_kHz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed */ + fs_kHz = SKP_DIV32_16( psEncC->API_fs_Hz, 1000 ); + fs_kHz = SKP_min( fs_kHz, psEncC->maxInternal_fs_kHz ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->API_fs_Hz > 8000 ) { + /* Accumulate the difference between the target rate and limit for switching down */ + psEncC->bitrateDiff += SKP_MUL( psEncC->PacketSize_ms, TargetRate_bps - psEncC->bitrate_threshold_down ); + psEncC->bitrateDiff = SKP_min( psEncC->bitrateDiff, 0 ); + + if( psEncC->vadFlag == NO_VOICE_ACTIVITY ) { /* Low speech activity */ + /* Check if we should switch down */ +#if SWITCH_TRANSITION_FILTERING + if( ( psEncC->sLP.transition_frame_no == 0 ) && /* Transition phase not active */ + ( psEncC->bitrateDiff <= -ACCUM_BITS_DIFF_THRESHOLD || /* Bitrate threshold is met */ + ( psEncC->sSWBdetect.WB_detected * psEncC->fs_kHz == 24 ) ) ) { /* Forced down-switching due to WB input */ + psEncC->sLP.transition_frame_no = 1; /* Begin transition phase */ + psEncC->sLP.mode = 0; /* Switch down */ + } else if( + ( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES_DOWN ) && /* Transition phase complete */ + ( psEncC->sLP.mode == 0 ) ) { /* Ready to switch down */ + psEncC->sLP.transition_frame_no = 0; /* Ready for new transition phase */ +#else + if( psEncC->bitrateDiff <= -ACCUM_BITS_DIFF_THRESHOLD ) { /* Bitrate threshold is met */ +#endif + psEncC->bitrateDiff = 0; + + /* Switch to a lower sample frequency */ + if( psEncC->fs_kHz == 24 ) { + fs_kHz = 16; + } else if( psEncC->fs_kHz == 16 ) { + fs_kHz = 12; + } else { + SKP_assert( psEncC->fs_kHz == 12 ); + fs_kHz = 8; + } + } + + /* Check if we should switch up */ + if( ( ( psEncC->fs_kHz * 1000 < psEncC->API_fs_Hz ) && + ( TargetRate_bps >= psEncC->bitrate_threshold_up ) && + ( psEncC->sSWBdetect.WB_detected * psEncC->fs_kHz < 16 ) ) && + ( ( ( psEncC->fs_kHz == 16 ) && ( psEncC->maxInternal_fs_kHz >= 24 ) ) || + ( ( psEncC->fs_kHz == 12 ) && ( psEncC->maxInternal_fs_kHz >= 16 ) ) || + ( ( psEncC->fs_kHz == 8 ) && ( psEncC->maxInternal_fs_kHz >= 12 ) ) ) +#if SWITCH_TRANSITION_FILTERING + && ( psEncC->sLP.transition_frame_no == 0 ) ) { /* No transition phase running, ready to switch */ + psEncC->sLP.mode = 1; /* Switch up */ +#else + ) { +#endif + psEncC->bitrateDiff = 0; + + /* Switch to a higher sample frequency */ + if( psEncC->fs_kHz == 8 ) { + fs_kHz = 12; + } else if( psEncC->fs_kHz == 12 ) { + fs_kHz = 16; + } else { + SKP_assert( psEncC->fs_kHz == 16 ); + fs_kHz = 24; + } + } + } + } + +#if SWITCH_TRANSITION_FILTERING + /* After switching up, stop transition filter during speech inactivity */ + if( ( psEncC->sLP.mode == 1 ) && + ( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES_UP ) && + ( psEncC->vadFlag == NO_VOICE_ACTIVITY ) ) { + + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + SKP_memset( psEncC->sLP.In_LP_State, 0, 2 * sizeof( SKP_int32 ) ); + } +#endif + } + + + + return fs_kHz; +} diff --git a/pkg/silk/csilk/SKP_Silk_control_codec_FIX.c b/pkg/silk/csilk/SKP_Silk_control_codec_FIX.c new file mode 100644 index 0000000..a24853c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_control_codec_FIX.c @@ -0,0 +1,402 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_setup_complexity.h" + +SKP_INLINE SKP_int SKP_Silk_setup_resamplers_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_packetsize_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int PacketSize_ms /* I Packet length (ms) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_fs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_rate_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int32 TargetRate_bps /* I Target max bitrate (if SNR_dB == 0) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_LBRR_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk encoder state FIX */ +); + +/* Control encoder */ +SKP_int SKP_Silk_control_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state */ + const SKP_int PacketSize_ms, /* I Packet length (ms) */ + const SKP_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const SKP_int PacketLoss_perc, /* I Packet loss rate (in percent) */ + const SKP_int DTX_enabled, /* I Enable / disable DTX */ + const SKP_int Complexity /* I Complexity (0->low; 1->medium; 2->high) */ +) +{ + SKP_int fs_kHz, ret = 0; + + if( psEnc->sCmn.controlled_since_last_payload != 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 += SKP_Silk_setup_resamplers_FIX( 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 = SKP_Silk_control_audio_bandwidth( &psEnc->sCmn, TargetRate_bps ); + + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += SKP_Silk_setup_resamplers_FIX( psEnc, fs_kHz ); + + /********************************************/ + /* Set packet size */ + /********************************************/ + ret += SKP_Silk_setup_packetsize_FIX( psEnc, PacketSize_ms ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += SKP_Silk_setup_fs_FIX( psEnc, fs_kHz ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += SKP_Silk_setup_complexity( &psEnc->sCmn, Complexity ); + + /********************************************/ + /* Set bitrate/coding quality */ + /********************************************/ + ret += SKP_Silk_setup_rate_FIX( psEnc, TargetRate_bps ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + if( ( PacketLoss_perc < 0 ) || ( PacketLoss_perc > 100 ) ) { + ret = SKP_SILK_ENC_INVALID_LOSS_RATE; + } + psEnc->sCmn.PacketLoss_perc = PacketLoss_perc; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += SKP_Silk_setup_LBRR_FIX( psEnc ); + + /********************************************/ + /* Set DTX mode */ + /********************************************/ + if( DTX_enabled < 0 || DTX_enabled > 1 ) { + ret = SKP_SILK_ENC_INVALID_DTX_SETTING; + } + psEnc->sCmn.useDTX = DTX_enabled; + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +/* Control low bitrate redundancy usage */ +void SKP_Silk_LBRR_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I Encoder state FIX */ + SKP_Silk_encoder_control *psEncCtrlC /* I/O Encoder control */ +) +{ + SKP_int LBRR_usage; + + if( psEnc->sCmn.LBRR_enabled ) { + /* Control LBRR */ + + /* Usage Control based on sensitivity and packet loss caracteristics */ + /* For now only enable adding to next for active frames. Make more complex later */ + LBRR_usage = SKP_SILK_NO_LBRR; + if( psEnc->speech_activity_Q8 > SKP_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) && psEnc->sCmn.PacketLoss_perc > LBRR_LOSS_THRES ) { // nb! maybe multiply loss prob and speech activity + LBRR_usage = SKP_SILK_ADD_LBRR_TO_PLUS1; + } + psEncCtrlC->LBRR_usage = LBRR_usage; + } else { + psEncCtrlC->LBRR_usage = SKP_SILK_NO_LBRR; + } +} + +SKP_INLINE SKP_int SKP_Silk_setup_resamplers_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + 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 += SKP_Silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000 ); + } else { + /* Allocate space for worst case temporary upsampling, 8 to 48 kHz, so a factor 6 */ + SKP_int16 x_buf_API_fs_Hz[ ( 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ) * ( MAX_API_FS_KHZ / 8 ) ]; + + SKP_int32 nSamples_temp = SKP_LSHIFT( psEnc->sCmn.frame_length, 1 ) + LA_SHAPE_MS * psEnc->sCmn.fs_kHz; + + if( SKP_SMULBB( fs_kHz, 1000 ) < psEnc->sCmn.API_fs_Hz && psEnc->sCmn.fs_kHz != 0 ) { + /* Resample buffered data in x_buf to API_fs_Hz */ + + SKP_Silk_resampler_state_struct temp_resampler_state; + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ret += SKP_Silk_resampler_init( &temp_resampler_state, SKP_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ret += SKP_Silk_resampler( &temp_resampler_state, x_buf_API_fs_Hz, psEnc->x_buf, nSamples_temp ); + + /* Calculate number of samples that has been temporarily upsampled */ + nSamples_temp = SKP_DIV32_16( nSamples_temp * psEnc->sCmn.API_fs_Hz, SKP_SMULBB( psEnc->sCmn.fs_kHz, 1000 ) ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += SKP_Silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, SKP_SMULBB( fs_kHz, 1000 ) ); + + } else { + /* Copy data */ + SKP_memcpy( x_buf_API_fs_Hz, psEnc->x_buf, nSamples_temp * sizeof( SKP_int16 ) ); + } + + if( 1000 * fs_kHz != psEnc->sCmn.API_fs_Hz ) { + /* Correct resampler state (unless resampling by a factor 1) by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += SKP_Silk_resampler( &psEnc->sCmn.resampler_state, psEnc->x_buf, x_buf_API_fs_Hz, nSamples_temp ); + } + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + return(ret); +} + +SKP_INLINE SKP_int SKP_Silk_setup_packetsize_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int PacketSize_ms /* I Packet length (ms) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + /* Set packet size */ + if( ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) && + ( PacketSize_ms != 80 ) && + ( PacketSize_ms != 100 ) ) { + ret = SKP_SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } else { + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + + /* Packet length changes. Reset LBRR buffer */ + SKP_Silk_LBRR_reset( &psEnc->sCmn ); + } + } + return(ret); +} + +SKP_INLINE SKP_int SKP_Silk_setup_fs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + /* Set internal sampling frequency */ + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + SKP_memset( &psEnc->sShape, 0, sizeof( SKP_Silk_shape_state_FIX ) ); + SKP_memset( &psEnc->sPrefilt, 0, sizeof( SKP_Silk_prefilter_state_FIX ) ); + SKP_memset( &psEnc->sPred, 0, sizeof( SKP_Silk_predict_state_FIX ) ); + SKP_memset( &psEnc->sCmn.sNSQ, 0, sizeof( SKP_Silk_nsq_state ) ); + SKP_memset( psEnc->sCmn.sNSQ_LBRR.xq, 0, ( 2 * MAX_FRAME_LENGTH ) * sizeof( SKP_int16 ) ); + SKP_memset( psEnc->sCmn.LBRR_buffer, 0, MAX_LBRR_DELAY * sizeof( SKP_SILK_LBRR_struct ) ); +#if SWITCH_TRANSITION_FILTERING + SKP_memset( psEnc->sCmn.sLP.In_LP_State, 0, 2 * sizeof( SKP_int32 ) ); + if( psEnc->sCmn.sLP.mode == 1 ) { + /* Begin transition phase */ + psEnc->sCmn.sLP.transition_frame_no = 1; + } else { + /* End transition phase */ + psEnc->sCmn.sLP.transition_frame_no = 0; + } +#endif + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesInPayloadBuf = 0; + psEnc->sCmn.nBytesInPayloadBuf = 0; + psEnc->sCmn.oldest_LBRR_idx = 0; + psEnc->sCmn.TargetRate_bps = 0; /* Ensures that psEnc->SNR_dB is recomputed */ + + SKP_memset( psEnc->sPred.prev_NLSFq_Q15, 0, MAX_LPC_ORDER * sizeof( SKP_int ) ); + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.prev_sigtype = SIG_TYPE_UNVOICED; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sPrefilt.lagPrev = 100; + psEnc->sShape.LastGainIndex = 1; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_inv_gain_Q16 = 65536; + psEnc->sCmn.sNSQ_LBRR.prev_inv_gain_Q16 = 65536; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_10; + psEnc->sCmn.psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_10; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_16; + psEnc->sCmn.psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_16; + } + psEnc->sCmn.frame_length = SKP_SMULBB( FRAME_LENGTH_MS, fs_kHz ); + psEnc->sCmn.subfr_length = SKP_DIV32_16( psEnc->sCmn.frame_length, NB_SUBFR ); + psEnc->sCmn.la_pitch = SKP_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sPred.min_pitch_lag = SKP_SMULBB( 3, fs_kHz ); + psEnc->sPred.max_pitch_lag = SKP_SMULBB( 18, fs_kHz ); + psEnc->sPred.pitch_LPC_win_length = SKP_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 24 ) { + psEnc->mu_LTP_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_SWB, 8 ); + psEnc->sCmn.bitrate_threshold_up = SKP_int32_MAX; + psEnc->sCmn.bitrate_threshold_down = SWB2WB_BITRATE_BPS; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->mu_LTP_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_WB, 8 ); + psEnc->sCmn.bitrate_threshold_up = WB2SWB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = WB2MB_BITRATE_BPS; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->mu_LTP_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_MB, 8 ); + psEnc->sCmn.bitrate_threshold_up = MB2WB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = MB2NB_BITRATE_BPS; + } else { + psEnc->mu_LTP_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_NB, 8 ); + psEnc->sCmn.bitrate_threshold_up = NB2MB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = 0; + } + psEnc->sCmn.fs_kHz_changed = 1; + + /* Check that settings are valid */ + SKP_assert( ( psEnc->sCmn.subfr_length * NB_SUBFR ) == psEnc->sCmn.frame_length ); + } + return( ret ); +} + +SKP_INLINE SKP_int SKP_Silk_setup_rate_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int32 TargetRate_bps /* I Target max bitrate (if SNR_dB == 0) */ +) +{ + SKP_int k, ret = SKP_SILK_NO_ERROR; + SKP_int32 frac_Q6; + const SKP_int32 *rateTable; + + /* Set bitrate/coding quality */ + if( TargetRate_bps != psEnc->sCmn.TargetRate_bps ) { + psEnc->sCmn.TargetRate_bps = TargetRate_bps; + + /* If new TargetRate_bps, translate to SNR_dB value */ + if( psEnc->sCmn.fs_kHz == 8 ) { + rateTable = TargetRate_table_NB; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + rateTable = TargetRate_table_MB; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + rateTable = TargetRate_table_WB; + } else { + rateTable = TargetRate_table_SWB; + } + for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) { + /* Find bitrate interval in table and interpolate */ + if( TargetRate_bps <= rateTable[ k ] ) { + frac_Q6 = SKP_DIV32( SKP_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ), + rateTable[ k ] - rateTable[ k - 1 ] ); + psEnc->SNR_dB_Q7 = SKP_LSHIFT( SNR_table_Q1[ k - 1 ], 6 ) + SKP_MUL( frac_Q6, SNR_table_Q1[ k ] - SNR_table_Q1[ k - 1 ] ); + break; + } + } + } + return( ret ); +} + +SKP_INLINE SKP_int SKP_Silk_setup_LBRR_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk encoder state FIX */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; +#if USE_LBRR + SKP_int32 LBRRRate_thres_bps; + + if( psEnc->sCmn.useInBandFEC < 0 || psEnc->sCmn.useInBandFEC > 1 ) { + ret = SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + + psEnc->sCmn.LBRR_enabled = psEnc->sCmn.useInBandFEC; + if( psEnc->sCmn.fs_kHz == 8 ) { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS - 9000; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS - 6000;; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS - 3000; + } else { + LBRRRate_thres_bps = INBAND_FEC_MIN_RATE_BPS; + } + + if( psEnc->sCmn.TargetRate_bps >= LBRRRate_thres_bps ) { + /* Set gain increase / rate reduction for LBRR usage */ + /* Coarsely tuned with PESQ for now. */ + /* Linear regression coefs G = 8 - 0.5 * loss */ + /* Meaning that at 16% loss main rate and redundant rate is the same, -> G = 0 */ + psEnc->sCmn.LBRR_GainIncreases = SKP_max_int( 8 - SKP_RSHIFT( psEnc->sCmn.PacketLoss_perc, 1 ), 0 ); + + /* Set main stream rate compensation */ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.PacketLoss_perc > LBRR_LOSS_THRES ) { + /* Tuned to give approx same mean / weighted bitrate as no inband FEC */ + psEnc->inBandFEC_SNR_comp_Q8 = SKP_FIX_CONST( 6.0f, 8 ) - SKP_LSHIFT( psEnc->sCmn.LBRR_GainIncreases, 7 ); + } else { + psEnc->inBandFEC_SNR_comp_Q8 = 0; + psEnc->sCmn.LBRR_enabled = 0; + } + } else { + psEnc->inBandFEC_SNR_comp_Q8 = 0; + psEnc->sCmn.LBRR_enabled = 0; + } +#else + if( INBandFEC_enabled != 0 ) { + ret = SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + psEnc->sCmn.LBRR_enabled = 0; +#endif + return ret; +} diff --git a/pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c b/pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c new file mode 100644 index 0000000..18b55c9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c @@ -0,0 +1,153 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Calculates correlation vector X'*t */ +void SKP_Silk_corrVector_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int16 *t, /* I target vector [L] */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + SKP_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const SKP_int rshifts /* I Right shifts of correlations */ +) +{ + SKP_int lag, i; + const SKP_int16 *ptr1, *ptr2; + SKP_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 += SKP_RSHIFT32( SKP_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + SKP_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = SKP_Silk_inner_prod_aligned( ptr1, ptr2, L ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void SKP_Silk_corrMatrix_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + const SKP_int head_room, /* I Desired headroom */ + SKP_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ]*/ + SKP_int *rshifts /* I/O Right shifts of correlations */ +) +{ + SKP_int i, j, lag, rshifts_local, head_room_rshifts; + SKP_int32 energy; + const SKP_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + SKP_Silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 ); + + /* Add shifts to get the desired head room */ + head_room_rshifts = SKP_max( head_room - SKP_Silk_CLZ32( energy ), 0 ); + + energy = SKP_RSHIFT32( energy, head_room_rshifts ); + rshifts_local += head_room_rshifts; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= SKP_RSHIFT32( SKP_SMULBB( x[ i ], x[ i ] ), rshifts_local ); + } + if( rshifts_local < *rshifts ) { + /* Adjust energy */ + energy = SKP_RSHIFT32( energy, *rshifts - rshifts_local ); + rshifts_local = *rshifts; + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = SKP_SUB32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) ); + energy = SKP_ADD32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) ); + matrix_ptr( XX, j, j, order ) = energy; + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( rshifts_local > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += SKP_RSHIFT32( SKP_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = SKP_SUB32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) ); + energy = SKP_ADD32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) ); + 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 = SKP_Silk_inner_prod_aligned( ptr1, ptr2, L ); + 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 = SKP_SUB32( energy, SKP_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = SKP_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 */ + } + } + *rshifts = rshifts_local; +} + diff --git a/pkg/silk/csilk/SKP_Silk_create_init_destroy.c b/pkg/silk/csilk/SKP_Silk_create_init_destroy.c new file mode 100644 index 0000000..355ca85 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_create_init_destroy.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + + +/************************/ +/* Init Decoder State */ +/************************/ +SKP_int SKP_Silk_init_decoder( + SKP_Silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + SKP_memset( psDec, 0, sizeof( SKP_Silk_decoder_state ) ); + /* Set sampling rate to 24 kHz, and init non-zero values */ + SKP_Silk_decoder_set_fs( psDec, 24 ); + + /* Used to deactivate e.g. LSF interpolation and fluctuation reduction */ + psDec->first_frame_after_reset = 1; + psDec->prev_inv_gain_Q16 = 65536; + + /* Reset CNG state */ + SKP_Silk_CNG_Reset( psDec ); + + SKP_Silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/pkg/silk/csilk/SKP_Silk_dec_API.c b/pkg/silk/csilk/SKP_Silk_dec_API.c new file mode 100644 index 0000000..ca031e3 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_dec_API.c @@ -0,0 +1,279 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SDK_API.h" +#include "SKP_Silk_main.h" + +/*********************/ +/* Decoder functions */ +/*********************/ + +SKP_int SKP_Silk_SDK_Get_Decoder_Size( SKP_int32 *decSizeBytes ) +{ + SKP_int ret = 0; + + *decSizeBytes = sizeof( SKP_Silk_decoder_state ); + + return ret; +} + +/* Reset decoder state */ +SKP_int SKP_Silk_SDK_InitDecoder( + void* decState /* I/O: State */ +) +{ + SKP_int ret = 0; + SKP_Silk_decoder_state *struc; + + struc = (SKP_Silk_decoder_state *)decState; + + ret = SKP_Silk_init_decoder( struc ); + + return ret; +} + +/* Decode a frame */ +SKP_int SKP_Silk_SDK_Decode( + void* decState, /* I/O: State */ + SKP_SILK_SDK_DecControlStruct* decControl, /* I/O: Control structure */ + SKP_int lostFlag, /* I: 0: no loss, 1 loss */ + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input Bytes */ + SKP_int16 *samplesOut, /* O: Decoded output speech vector */ + SKP_int16 *nSamplesOut /* I/O: Number of samples (vector/decoded) */ +) +{ + SKP_int ret = 0, used_bytes, prev_fs_kHz; + SKP_Silk_decoder_state *psDec; + SKP_int16 samplesOutInternal[ MAX_API_FS_KHZ * FRAME_LENGTH_MS ]; + SKP_int16 *pSamplesOutInternal; + + psDec = (SKP_Silk_decoder_state *)decState; + + /* We need this buffer to have room for an internal frame */ + pSamplesOutInternal = samplesOut; + if( psDec->fs_kHz * 1000 > decControl->API_sampleRate ) { + pSamplesOutInternal = samplesOutInternal; + } + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( psDec->moreInternalDecoderFrames == 0 ) { + /* First Frame in Payload */ + psDec->nFramesDecoded = 0; /* Used to count frames in packet */ + } + + if( psDec->moreInternalDecoderFrames == 0 && /* First frame in packet */ + lostFlag == 0 && /* Not packet loss */ + nBytesIn > MAX_ARITHM_BYTES ) { /* Too long payload */ + /* Avoid trying to decode a too large packet */ + lostFlag = 1; + ret = SKP_SILK_DEC_PAYLOAD_TOO_LARGE; + } + + /* Save previous sample frequency */ + prev_fs_kHz = psDec->fs_kHz; + + /* Call decoder for one frame */ + ret += SKP_Silk_decode_frame( psDec, pSamplesOutInternal, nSamplesOut, inData, nBytesIn, + lostFlag, &used_bytes ); + + if( used_bytes ) { /* Only Call if not a packet loss */ + if( psDec->nBytesLeft > 0 && psDec->FrameTermination == SKP_SILK_MORE_FRAMES && psDec->nFramesDecoded < 5 ) { + /* We have more frames in the Payload */ + psDec->moreInternalDecoderFrames = 1; + } else { + /* Last frame in Payload */ + psDec->moreInternalDecoderFrames = 0; + psDec->nFramesInPacket = psDec->nFramesDecoded; + + /* Track inband FEC usage */ + if( psDec->vadFlag == VOICE_ACTIVITY ) { + if( psDec->FrameTermination == SKP_SILK_LAST_FRAME ) { + psDec->no_FEC_counter++; + if( psDec->no_FEC_counter > NO_LBRR_THRES ) { + psDec->inband_FEC_offset = 0; + } + } else if( psDec->FrameTermination == SKP_SILK_LBRR_VER1 ) { + psDec->inband_FEC_offset = 1; /* FEC info with 1 packet delay */ + psDec->no_FEC_counter = 0; + } else if( psDec->FrameTermination == SKP_SILK_LBRR_VER2 ) { + psDec->inband_FEC_offset = 2; /* FEC info with 2 packets delay */ + psDec->no_FEC_counter = 0; + } + } + } + } + + if( MAX_API_FS_KHZ * 1000 < decControl->API_sampleRate || + 8000 > decControl->API_sampleRate ) { + ret = SKP_SILK_DEC_INVALID_SAMPLING_FREQUENCY; + return( ret ); + } + + /* Resample if needed */ + if( psDec->fs_kHz * 1000 != decControl->API_sampleRate ) { + SKP_int16 samplesOut_tmp[ MAX_API_FS_KHZ * FRAME_LENGTH_MS ]; + SKP_assert( psDec->fs_kHz <= MAX_API_FS_KHZ ); + + /* Copy to a tmp buffer as the resampling writes to samplesOut */ + SKP_memcpy( samplesOut_tmp, pSamplesOutInternal, *nSamplesOut * sizeof( SKP_int16 ) ); + + /* (Re-)initialize resampler state when switching internal sampling frequency */ + if( prev_fs_kHz != psDec->fs_kHz || psDec->prev_API_sampleRate != decControl->API_sampleRate ) { + ret = SKP_Silk_resampler_init( &psDec->resampler_state, SKP_SMULBB( psDec->fs_kHz, 1000 ), decControl->API_sampleRate ); + } + + /* Resample the output to API_sampleRate */ + ret += SKP_Silk_resampler( &psDec->resampler_state, samplesOut, samplesOut_tmp, *nSamplesOut ); + + /* Update the number of output samples */ + *nSamplesOut = SKP_DIV32( ( SKP_int32 )*nSamplesOut * decControl->API_sampleRate, psDec->fs_kHz * 1000 ); + } else if( prev_fs_kHz * 1000 > decControl->API_sampleRate ) { + SKP_memcpy( samplesOut, pSamplesOutInternal, *nSamplesOut * sizeof( SKP_int16 ) ); + } + + psDec->prev_API_sampleRate = decControl->API_sampleRate; + + /* Copy all parameters that are needed out of internal structure to the control stucture */ + decControl->frameSize = (SKP_uint16)( decControl->API_sampleRate / 50 ) ; + decControl->framesPerPacket = ( SKP_int )psDec->nFramesInPacket; + decControl->inBandFECOffset = ( SKP_int )psDec->inband_FEC_offset; + decControl->moreInternalDecoderFrames = ( SKP_int )psDec->moreInternalDecoderFrames; + + return ret; +} + +/* Function to find LBRR information in a packet */ +void SKP_Silk_SDK_search_for_LBRR( + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input Bytes */ + SKP_int lost_offset, /* I: Offset from lost packet */ + SKP_uint8 *LBRRData, /* O: LBRR payload */ + SKP_int16 *nLBRRBytes /* O: Number of LBRR Bytes */ +) +{ + SKP_Silk_decoder_state sDec; // Local decoder state to avoid interfering with running decoder */ + SKP_Silk_decoder_control sDecCtrl; + SKP_int TempQ[ MAX_FRAME_LENGTH ]; + + if( lost_offset < 1 || lost_offset > MAX_LBRR_DELAY ) { + /* No useful FEC in this packet */ + *nLBRRBytes = 0; + return; + } + + sDec.nFramesDecoded = 0; + sDec.fs_kHz = 0; /* Force update parameters LPC_order etc */ + sDec.lossCnt = 0; /* Avoid running bw expansion of the LPC parameters when searching for LBRR data */ + SKP_memset( sDec.prevNLSF_Q15, 0, MAX_LPC_ORDER * sizeof( SKP_int ) ); + SKP_Silk_range_dec_init( &sDec.sRC, inData, ( SKP_int32 )nBytesIn ); + + while(1) { + SKP_Silk_decode_parameters( &sDec, &sDecCtrl, TempQ, 0 ); + + if( sDec.sRC.error ) { + /* Corrupt stream */ + *nLBRRBytes = 0; + return; + }; + if( ( sDec.FrameTermination - 1 ) & lost_offset && sDec.FrameTermination > 0 && sDec.nBytesLeft >= 0 ) { + /* The wanted FEC is present in the packet */ + *nLBRRBytes = sDec.nBytesLeft; + SKP_memcpy( LBRRData, &inData[ nBytesIn - sDec.nBytesLeft ], sDec.nBytesLeft * sizeof( SKP_uint8 ) ); + break; + } + if( sDec.nBytesLeft > 0 && sDec.FrameTermination == SKP_SILK_MORE_FRAMES ) { + sDec.nFramesDecoded++; + } else { + LBRRData = NULL; + *nLBRRBytes = 0; + break; + } + } +} + +/* Getting type of content for a packet */ +void SKP_Silk_SDK_get_TOC( + const SKP_uint8 *inData, /* I: Encoded input vector */ + const SKP_int nBytesIn, /* I: Number of input bytes */ + SKP_Silk_TOC_struct *Silk_TOC /* O: Type of content */ +) +{ + SKP_Silk_decoder_state sDec; // Local Decoder state to avoid interfering with running decoder */ + SKP_Silk_decoder_control sDecCtrl; + SKP_int TempQ[ MAX_FRAME_LENGTH ]; + + sDec.nFramesDecoded = 0; + sDec.fs_kHz = 0; /* Force update parameters LPC_order etc */ + SKP_Silk_range_dec_init( &sDec.sRC, inData, ( SKP_int32 )nBytesIn ); + + Silk_TOC->corrupt = 0; + while( 1 ) { + SKP_Silk_decode_parameters( &sDec, &sDecCtrl, TempQ, 0 ); + + Silk_TOC->vadFlags[ sDec.nFramesDecoded ] = sDec.vadFlag; + Silk_TOC->sigtypeFlags[ sDec.nFramesDecoded ] = sDecCtrl.sigtype; + + if( sDec.sRC.error ) { + /* Corrupt stream */ + Silk_TOC->corrupt = 1; + break; + }; + + if( sDec.nBytesLeft > 0 && sDec.FrameTermination == SKP_SILK_MORE_FRAMES ) { + sDec.nFramesDecoded++; + } else { + break; + } + } + if( Silk_TOC->corrupt || sDec.FrameTermination == SKP_SILK_MORE_FRAMES || + sDec.nFramesInPacket > SILK_MAX_FRAMES_PER_PACKET ) { + /* Corrupt packet */ + SKP_memset( Silk_TOC, 0, sizeof( SKP_Silk_TOC_struct ) ); + Silk_TOC->corrupt = 1; + } else { + Silk_TOC->framesInPacket = sDec.nFramesDecoded + 1; + Silk_TOC->fs_kHz = sDec.fs_kHz; + if( sDec.FrameTermination == SKP_SILK_LAST_FRAME ) { + Silk_TOC->inbandLBRR = sDec.FrameTermination; + } else { + Silk_TOC->inbandLBRR = sDec.FrameTermination - 1; + } + } +} + +/**************************/ +/* Get the version number */ +/**************************/ +/* Return a pointer to string specifying the version */ +const char *SKP_Silk_SDK_get_version() +{ + static const char version[] = "1.0.9.6"; + return version; +} diff --git a/pkg/silk/csilk/SKP_Silk_decode_core.c b/pkg/silk/csilk/SKP_Silk_decode_core.c new file mode 100644 index 0000000..247f24d --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decode_core.c @@ -0,0 +1,314 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + + +void SKP_Silk_decode_short_term_prediction( +SKP_int32 *vec_Q10, +SKP_int32 *pres_Q10, +SKP_int32 *sLPC_Q14, +SKP_int16 *A_Q12_tmp, +SKP_int LPC_order, +SKP_int subfr_length +); + + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void SKP_Silk_decode_core( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I Decoder control */ + SKP_int16 xq[], /* O Decoded speech */ + const SKP_int q[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +) +{ + SKP_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, sigtype; + SKP_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + SKP_int16 sLTP[ MAX_FRAME_LENGTH ]; + SKP_int32 LTP_pred_Q14, Gain_Q16, inv_gain_Q16, inv_gain_Q32, gain_adj_Q16, rand_seed, offset_Q10, dither; + SKP_int32 *pred_lag_ptr, *pexc_Q10, *pres_Q10; + SKP_int32 vec_Q10[ MAX_FRAME_LENGTH / NB_SUBFR ]; + SKP_int32 FiltState[ MAX_LPC_ORDER ]; + + SKP_assert( psDec->prev_inv_gain_Q16 != 0 ); + + offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psDecCtrl->sigtype ][ psDecCtrl->QuantOffsetType ]; + + if( psDecCtrl->NLSFInterpCoef_Q2 < ( 1 << 2 ) ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + + /* Decode excitation */ + rand_seed = psDecCtrl->Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = SKP_RAND( rand_seed ); + /* dither = rand_seed < 0 ? 0xFFFFFFFF : 0; */ + dither = SKP_RSHIFT( rand_seed, 31 ); + + psDec->exc_Q10[ i ] = SKP_LSHIFT( ( SKP_int32 )q[ i ], 10 ) + offset_Q10; + psDec->exc_Q10[ i ] = ( psDec->exc_Q10[ i ] ^ dither ) - dither; + + rand_seed += q[ i ]; + } + + + pexc_Q10 = psDec->exc_Q10; + pres_Q10 = psDec->res_Q10; + pxq = &psDec->outBuf[ psDec->frame_length ]; + sLTP_buf_idx = psDec->frame_length; + /* Loop over subframes */ + for( k = 0; k < NB_SUBFR; k++ ) { + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + SKP_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( SKP_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + Gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + sigtype = psDecCtrl->sigtype; + + inv_gain_Q16 = SKP_INVERSE32_varQ( SKP_max( Gain_Q16, 1 ), 32 ); + inv_gain_Q16 = SKP_min( inv_gain_Q16, SKP_int16_MAX ); + + /* Calculate Gain adjustment factor */ + gain_adj_Q16 = ( SKP_int32 )1 << 16; + if( inv_gain_Q16 != psDec->prev_inv_gain_Q16 ) { + gain_adj_Q16 = SKP_DIV32_varQ( inv_gain_Q16, psDec->prev_inv_gain_Q16, 16 ); + } + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prev_sigtype == SIG_TYPE_VOICED && + psDecCtrl->sigtype == SIG_TYPE_UNVOICED && k < ( NB_SUBFR >> 1 ) ) { + + SKP_memset( B_Q14, 0, LTP_ORDER * sizeof( SKP_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = ( SKP_int16 )1 << 12; /* 0.25 */ + + sigtype = SIG_TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( sigtype == SIG_TYPE_VOICED ) { + /* Voiced */ + + lag = psDecCtrl->pitchL[ k ]; + /* Re-whitening */ + if( ( k & ( 3 - SKP_LSHIFT( NLSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->frame_length - lag - psDec->LPC_order - LTP_ORDER / 2; + SKP_assert( start_idx >= 0 ); + SKP_assert( start_idx <= psDec->frame_length - psDec->LPC_order ); + + SKP_memset( FiltState, 0, psDec->LPC_order * sizeof( SKP_int32 ) ); /* Not really necessary, but Valgrind and Coverity will complain otherwise */ + SKP_Silk_MA_Prediction( &psDec->outBuf[ start_idx + k * ( psDec->frame_length >> 2 ) ], + A_Q12, FiltState, sLTP + start_idx, psDec->frame_length - start_idx, psDec->LPC_order ); + + /* After rewhitening the LTP state is unscaled */ + inv_gain_Q32 = SKP_LSHIFT( inv_gain_Q16, 16 ); + if( k == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q32 = SKP_LSHIFT( SKP_SMULWB( inv_gain_Q32, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < (lag + LTP_ORDER/2); i++ ) { + psDec->sLTP_Q16[ sLTP_buf_idx - i - 1 ] = SKP_SMULWB( inv_gain_Q32, sLTP[ psDec->frame_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != ( SKP_int32 )1 << 16 ) { + for( i = 0; i < ( lag + LTP_ORDER / 2 ); i++ ) { + psDec->sLTP_Q16[ sLTP_buf_idx - i - 1 ] = SKP_SMULWW( gain_adj_Q16, psDec->sLTP_Q16[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + psDec->sLPC_Q14[ i ] = SKP_SMULWW( gain_adj_Q16, psDec->sLPC_Q14[ i ] ); + } + + /* Save inv_gain */ + SKP_assert( inv_gain_Q16 != 0 ); + psDec->prev_inv_gain_Q16 = inv_gain_Q16; + + /* Long-term prediction */ + if( sigtype == SIG_TYPE_VOICED ) { + /* Setup pointer */ + pred_lag_ptr = &psDec->sLTP_Q16[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + LTP_pred_Q14 = SKP_SMULWB( pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q14 = SKP_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC residual */ + pres_Q10[ i ] = SKP_ADD32( pexc_Q10[ i ], SKP_RSHIFT_ROUND( LTP_pred_Q14, 4 ) ); + + /* Update states */ + psDec->sLTP_Q16[ sLTP_buf_idx ] = SKP_LSHIFT( pres_Q10[ i ], 6 ); + sLTP_buf_idx++; + } + } else { + SKP_memcpy( pres_Q10, pexc_Q10, psDec->subfr_length * sizeof( SKP_int32 ) ); + } + + SKP_Silk_decode_short_term_prediction(vec_Q10, pres_Q10, psDec->sLPC_Q14,A_Q12_tmp,psDec->LPC_order,psDec->subfr_length); + + /* Scale with Gain */ + for( i = 0; i < psDec->subfr_length; i++ ) { + pxq[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SMULWW( vec_Q10[ i ], Gain_Q16 ), 10 ) ); + } + + /* Update LPC filter state */ + SKP_memcpy( psDec->sLPC_Q14, &psDec->sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( SKP_int32 ) ); + pexc_Q10 += psDec->subfr_length; + pres_Q10 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Copy to output */ + SKP_memcpy( xq, &psDec->outBuf[ psDec->frame_length ], psDec->frame_length * sizeof( SKP_int16 ) ); + +} + +#if EMBEDDED_ARM<5 +void SKP_Silk_decode_short_term_prediction( +SKP_int32 *vec_Q10, +SKP_int32 *pres_Q10, +SKP_int32 *sLPC_Q14, +SKP_int16 *A_Q12_tmp, +SKP_int LPC_order, +SKP_int subfr_length +) +{ + SKP_int i; + SKP_int32 LPC_pred_Q10; + #if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp; + /* Short term prediction */ + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + if( LPC_order == 16 ) { + for( i = 0; i < subfr_length; i++ ) { + /* unrolled */ + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 0 ] ); /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], Atmp ); + + /* Add prediction to LPC residual */ + vec_Q10[ i ] = SKP_ADD32( pres_Q10[ i ], LPC_pred_Q10 ); + + /* Update states */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT_ovflw( vec_Q10[ i ], 4 ); + } + } else { + SKP_assert( LPC_order == 10 ); + for( i = 0; i < subfr_length; i++ ) { + /* unrolled */ + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 0 ] ); /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); + + /* Add prediction to LPC residual */ + vec_Q10[ i ] = SKP_ADD32( pres_Q10[ i ], LPC_pred_Q10 ); + + /* Update states */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT_ovflw( vec_Q10[ i ], 4 ); + } + } +#else + SKP_int j; + for( i = 0; i < subfr_length; i++ ) { + /* Partially unrolled */ + LPC_pred_Q10 = SKP_SMULWB( sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + + for( j = 10; j < LPC_order; j ++ ) { + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - j - 1 ], A_Q12_tmp[ j ] ); + } + + /* Add prediction to LPC residual */ + vec_Q10[ i ] = SKP_ADD32( pres_Q10[ i ], LPC_pred_Q10 ); + + /* Update states */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = SKP_LSHIFT_ovflw( vec_Q10[ i ], 4 ); + } +#endif +} +#endif + + + diff --git a/pkg/silk/csilk/SKP_Silk_decode_frame.c b/pkg/silk/csilk/SKP_Silk_decode_frame.c new file mode 100644 index 0000000..c0ff322 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decode_frame.c @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#include "SKP_Silk_main.h" +#include "SKP_Silk_PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +SKP_int SKP_Silk_decode_frame( + SKP_Silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + SKP_int16 pOut[], /* O Pointer to output speech frame */ + SKP_int16 *pN, /* O Pointer to size of output frame */ + const SKP_uint8 pCode[], /* I Pointer to payload */ + const SKP_int nBytes, /* I Payload length */ + SKP_int action, /* I Action from Jitter Buffer */ + SKP_int *decBytes /* O Used bytes to decode this frame */ +) +{ + SKP_Silk_decoder_control sDecCtrl; + SKP_int L, fs_Khz_old, ret = 0; + SKP_int Pulses[ MAX_FRAME_LENGTH ]; + + + L = psDec->frame_length; + sDecCtrl.LTP_scale_Q14 = 0; + + /* Safety checks */ + SKP_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + /********************************************/ + /* Decode Frame if packet is not lost */ + /********************************************/ + *decBytes = 0; + if( action == 0 ) { + /********************************************/ + /* Initialize arithmetic coder */ + /********************************************/ + fs_Khz_old = psDec->fs_kHz; + if( psDec->nFramesDecoded == 0 ) { + /* Initialize range decoder state */ + SKP_Silk_range_dec_init( &psDec->sRC, pCode, nBytes ); + } + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + SKP_Silk_decode_parameters( psDec, &sDecCtrl, Pulses, 1 ); + + + if( psDec->sRC.error ) { + psDec->nBytesLeft = 0; + + action = 1; /* PLC operation */ + /* revert fs if changed in decode_parameters */ + SKP_Silk_decoder_set_fs( psDec, fs_Khz_old ); + + /* Avoid crashing */ + *decBytes = psDec->sRC.bufferLength; + + if( psDec->sRC.error == RANGE_CODER_DEC_PAYLOAD_TOO_LONG ) { + ret = SKP_SILK_DEC_PAYLOAD_TOO_LARGE; + } else { + ret = SKP_SILK_DEC_PAYLOAD_ERROR; + } + } else { + *decBytes = psDec->sRC.bufferLength - psDec->nBytesLeft; + psDec->nFramesDecoded++; + + /* Update lengths. Sampling frequency could have changed */ + L = psDec->frame_length; + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + SKP_Silk_decode_core( psDec, &sDecCtrl, pOut, Pulses ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + SKP_Silk_PLC( psDec, &sDecCtrl, pOut, L, action ); + + psDec->lossCnt = 0; + psDec->prev_sigtype = sDecCtrl.sigtype; + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } + } + /*************************************************************/ + /* Generate Concealment frame if packet is lost, or corrupt */ + /*************************************************************/ + if( action == 1 ) { + /* Handle packet loss by extrapolation */ + SKP_Silk_PLC( psDec, &sDecCtrl, pOut, L, action ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + SKP_memcpy( psDec->outBuf, pOut, L * sizeof( SKP_int16 ) ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + SKP_Silk_PLC_glue_frames( psDec, &sDecCtrl, pOut, L ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + SKP_Silk_CNG( psDec, &sDecCtrl, pOut , L ); + + /********************************************/ + /* HP filter output */ + /********************************************/ + SKP_assert( ( ( psDec->fs_kHz == 12 ) && ( L % 3 ) == 0 ) || + ( ( psDec->fs_kHz != 12 ) && ( L % 2 ) == 0 ) ); + SKP_Silk_biquad( pOut, psDec->HP_B, psDec->HP_A, psDec->HPState, pOut, L ); + + /********************************************/ + /* set output frame length */ + /********************************************/ + *pN = ( SKP_int16 )L; + + /* Update some decoder state variables */ + psDec->lagPrev = sDecCtrl.pitchL[ NB_SUBFR - 1 ]; + + + return ret; +} diff --git a/pkg/silk/csilk/SKP_Silk_decode_parameters.c b/pkg/silk/csilk/SKP_Silk_decode_parameters.c new file mode 100644 index 0000000..108a939 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decode_parameters.c @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Decode parameters from payload */ +void SKP_Silk_decode_parameters( + SKP_Silk_decoder_state *psDec, /* I/O State */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int fullDecoding /* I Flag to tell if only arithmetic decoding */ +) +{ + SKP_int i, k, Ix, fs_kHz_dec, nBytesUsed; + SKP_int Ixs[ NB_SUBFR ]; + SKP_int GainsIndices[ NB_SUBFR ]; + SKP_int NLSFIndices[ NLSF_MSVQ_MAX_CB_STAGES ]; + SKP_int pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const SKP_int16 *cbk_ptr_Q14; + const SKP_Silk_NLSF_CB_struct *psNLSF_CB = NULL; + SKP_Silk_range_coder_state *psRC = &psDec->sRC; + + /************************/ + /* Decode sampling rate */ + /************************/ + /* only done for first frame of packet */ + if( psDec->nFramesDecoded == 0 ) { + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_SamplingRates_CDF, SKP_Silk_SamplingRates_offset ); + + /* check that sampling rate is supported */ + if( Ix < 0 || Ix > 3 ) { + psRC->error = RANGE_CODER_ILLEGAL_SAMPLING_RATE; + return; + } + fs_kHz_dec = SKP_Silk_SamplingRates_table[ Ix ]; + SKP_Silk_decoder_set_fs( psDec, fs_kHz_dec ); + } + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( psDec->nFramesDecoded == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_type_offset_CDF, SKP_Silk_type_offset_CDF_offset ); + } else { + /* condidtional coding */ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_type_offset_joint_CDF[ psDec->typeOffsetPrev ], + SKP_Silk_type_offset_CDF_offset ); + } + psDecCtrl->sigtype = SKP_RSHIFT( Ix, 1 ); + psDecCtrl->QuantOffsetType = Ix & 1; + psDec->typeOffsetPrev = Ix; + + /****************/ + /* Decode gains */ + /****************/ + /* first subframe */ + if( psDec->nFramesDecoded == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_decoder( &GainsIndices[ 0 ], psRC, SKP_Silk_gain_CDF[ psDecCtrl->sigtype ], SKP_Silk_gain_CDF_offset ); + } else { + /* condidtional coding */ + SKP_Silk_range_decoder( &GainsIndices[ 0 ], psRC, SKP_Silk_delta_gain_CDF, SKP_Silk_delta_gain_CDF_offset ); + } + + /* remaining subframes */ + for( i = 1; i < NB_SUBFR; i++ ) { + SKP_Silk_range_decoder( &GainsIndices[ i ], psRC, SKP_Silk_delta_gain_CDF, SKP_Silk_delta_gain_CDF_offset ); + } + + /* Dequant Gains */ + SKP_Silk_gains_dequant( psDecCtrl->Gains_Q16, GainsIndices, &psDec->LastGainIndex, psDec->nFramesDecoded ); + /****************/ + /* Decode NLSFs */ + /****************/ + /* Set pointer to NLSF VQ CB for the current signal type */ + psNLSF_CB = psDec->psNLSF_CB[ psDecCtrl->sigtype ]; + + /* Range decode NLSF path */ + SKP_Silk_range_decoder_multi( NLSFIndices, psRC, psNLSF_CB->StartPtr, psNLSF_CB->MiddleIx, psNLSF_CB->nStages ); + + /* From the NLSF path, decode an NLSF vector */ + SKP_Silk_NLSF_MSVQ_decode( pNLSF_Q15, psNLSF_CB, NLSFIndices, psDec->LPC_order ); + + /************************************/ + /* Decode NLSF interpolation factor */ + /************************************/ + SKP_Silk_range_decoder( &psDecCtrl->NLSFInterpCoef_Q2, psRC, SKP_Silk_NLSF_interpolation_factor_CDF, + SKP_Silk_NLSF_interpolation_factor_offset ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDecCtrl->NLSFInterpCoef_Q2 = 4; + } + + if( fullDecoding ) { + /* Convert NLSF parameters to AR prediction filter coefficients */ + SKP_Silk_NLSF2A_stable( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order ); + + if( psDecCtrl->NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + SKP_RSHIFT( SKP_MUL( psDecCtrl->NLSFInterpCoef_Q2, + ( pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ) ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + SKP_Silk_NLSF2A_stable( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order ); + } else { + /* Copy LPC coefficients for first half from second half */ + SKP_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], + psDec->LPC_order * sizeof( SKP_int16 ) ); + } + } + + SKP_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( SKP_int ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + SKP_Silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + SKP_Silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDecCtrl->sigtype == SIG_TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + if( psDec->fs_kHz == 8 ) { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_NB_CDF, SKP_Silk_pitch_lag_NB_CDF_offset ); + } else if( psDec->fs_kHz == 12 ) { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_MB_CDF, SKP_Silk_pitch_lag_MB_CDF_offset ); + } else if( psDec->fs_kHz == 16 ) { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_WB_CDF, SKP_Silk_pitch_lag_WB_CDF_offset ); + } else { + SKP_Silk_range_decoder( &Ixs[ 0 ], psRC, SKP_Silk_pitch_lag_SWB_CDF, SKP_Silk_pitch_lag_SWB_CDF_offset ); + } + + /* Get countour index */ + if( psDec->fs_kHz == 8 ) { + /* Less codevectors used in 8 khz mode */ + SKP_Silk_range_decoder( &Ixs[ 1 ], psRC, SKP_Silk_pitch_contour_NB_CDF, SKP_Silk_pitch_contour_NB_CDF_offset ); + } else { + /* Joint for 12, 16, and 24 khz */ + SKP_Silk_range_decoder( &Ixs[ 1 ], psRC, SKP_Silk_pitch_contour_CDF, SKP_Silk_pitch_contour_CDF_offset ); + } + + /* Decode pitch values */ + SKP_Silk_decode_pitch( Ixs[ 0 ], Ixs[ 1 ], psDecCtrl->pitchL, psDec->fs_kHz ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + SKP_Silk_range_decoder( &psDecCtrl->PERIndex, psRC, SKP_Silk_LTP_per_index_CDF, + SKP_Silk_LTP_per_index_CDF_offset ); + + /* Decode Codebook Index */ + cbk_ptr_Q14 = SKP_Silk_LTP_vq_ptrs_Q14[ psDecCtrl->PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < NB_SUBFR; k++ ) { + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_LTP_gain_CDF_ptrs[ psDecCtrl->PERIndex ], + SKP_Silk_LTP_gain_CDF_offsets[ psDecCtrl->PERIndex ] ); + + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = cbk_ptr_Q14[ Ix * LTP_ORDER + i ]; + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_LTPscale_CDF, SKP_Silk_LTPscale_offset ); + psDecCtrl->LTP_scale_Q14 = SKP_Silk_LTPScales_table_Q14[ Ix ]; + } else { + SKP_assert( psDecCtrl->sigtype == SIG_TYPE_UNVOICED ); + SKP_memset( psDecCtrl->pitchL, 0, NB_SUBFR * sizeof( SKP_int ) ); + SKP_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * NB_SUBFR * sizeof( SKP_int16 ) ); + psDecCtrl->PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } + + /***************/ + /* Decode seed */ + /***************/ + SKP_Silk_range_decoder( &Ix, psRC, SKP_Silk_Seed_CDF, SKP_Silk_Seed_offset ); + psDecCtrl->Seed = ( SKP_int32 )Ix; + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + SKP_Silk_decode_pulses( psRC, psDecCtrl, q, psDec->frame_length ); + + /*********************************************/ + /* Decode VAD flag */ + /*********************************************/ + SKP_Silk_range_decoder( &psDec->vadFlag, psRC, SKP_Silk_vadflag_CDF, SKP_Silk_vadflag_offset ); + + /**************************************/ + /* Decode Frame termination indicator */ + /**************************************/ + SKP_Silk_range_decoder( &psDec->FrameTermination, psRC, SKP_Silk_FrameTermination_CDF, SKP_Silk_FrameTermination_offset ); + + /****************************************/ + /* get number of bytes used so far */ + /****************************************/ + SKP_Silk_range_coder_get_length( psRC, &nBytesUsed ); + psDec->nBytesLeft = psRC->bufferLength - nBytesUsed; + if( psDec->nBytesLeft < 0 ) { + psRC->error = RANGE_CODER_READ_BEYOND_BUFFER; + } + + /****************************************/ + /* check remaining bits in last byte */ + /****************************************/ + if( psDec->nBytesLeft == 0 ) { + SKP_Silk_range_coder_check_after_decoding( psRC ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_decode_pitch.c b/pkg/silk/csilk/SKP_Silk_decode_pitch.c new file mode 100644 index 0000000..38b7aa7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decode_pitch.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +void SKP_Silk_decode_pitch( + SKP_int lagIndex, /* I */ + SKP_int contourIndex, /* O */ + SKP_int pitch_lags[], /* O 4 pitch values */ + SKP_int Fs_kHz /* I sampling frequency (kHz) */ +) +{ + SKP_int lag, i, min_lag; + + min_lag = SKP_SMULBB( PITCH_EST_MIN_LAG_MS, Fs_kHz ); + + /* Only for 24 / 16 kHz version for now */ + lag = min_lag + lagIndex; + if( Fs_kHz == 8 ) { + /* Only a small codebook for 8 khz */ + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + pitch_lags[ i ] = lag + SKP_Silk_CB_lags_stage2[ i ][ contourIndex ]; + } + } else { + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + pitch_lags[ i ] = lag + SKP_Silk_CB_lags_stage3[ i ][ contourIndex ]; + } + } +} diff --git a/pkg/silk/csilk/SKP_Silk_decode_pulses.c b/pkg/silk/csilk/SKP_Silk_decode_pulses.c new file mode 100644 index 0000000..119553f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decode_pulses.c @@ -0,0 +1,105 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void SKP_Silk_decode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int frame_length /* I Frame length (preliminary) */ +) +{ + SKP_int i, j, k, iter, abs_q, nLS, bit; + SKP_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + SKP_int *pulses_ptr; + const SKP_uint16 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + SKP_Silk_range_decoder( &psDecCtrl->RateLevelIndex, psRC, + SKP_Silk_rate_levels_CDF[ psDecCtrl->sigtype ], SKP_Silk_rate_levels_CDF_offset ); + + /* Calculate number of shell blocks */ + iter = frame_length / SHELL_CODEC_FRAME_LENGTH; + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = SKP_Silk_pulses_per_block_CDF[ psDecCtrl->RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + SKP_Silk_range_decoder( &sum_pulses[ i ], psRC, cdf_ptr, SKP_Silk_pulses_per_block_CDF_offset ); + + /* LSB indication */ + while( sum_pulses[ i ] == ( MAX_PULSES + 1 ) ) { + nLshifts[ i ]++; + SKP_Silk_range_decoder( &sum_pulses[ i ], psRC, + SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS - 1 ], SKP_Silk_pulses_per_block_CDF_offset ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + SKP_Silk_shell_decoder( &q[ SKP_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRC, sum_pulses[ i ] ); + } else { + SKP_memset( &q[ SKP_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( SKP_int ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &q[ SKP_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = SKP_LSHIFT( abs_q, 1 ); + SKP_Silk_range_decoder( &bit, psRC, SKP_Silk_lsb_CDF, 1 ); + abs_q += bit; + } + pulses_ptr[ k ] = abs_q; + } + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + SKP_Silk_decode_signs( psRC, q, frame_length, psDecCtrl->sigtype, + psDecCtrl->QuantOffsetType, psDecCtrl->RateLevelIndex); +} diff --git a/pkg/silk/csilk/SKP_Silk_decoder_set_fs.c b/pkg/silk/csilk/SKP_Silk_decoder_set_fs.c new file mode 100644 index 0000000..b4cd08b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decoder_set_fs.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Set decoder sampling rate */ +void SKP_Silk_decoder_set_fs( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state pointer */ + SKP_int fs_kHz /* I Sampling frequency (kHz) */ +) +{ + if( psDec->fs_kHz != fs_kHz ) { + psDec->fs_kHz = fs_kHz; + psDec->frame_length = SKP_SMULBB( FRAME_LENGTH_MS, fs_kHz ); + psDec->subfr_length = SKP_SMULBB( FRAME_LENGTH_MS / NB_SUBFR, fs_kHz ); + if( psDec->fs_kHz == 8 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_10; + psDec->psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_10; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB[ 0 ] = &SKP_Silk_NLSF_CB0_16; + psDec->psNLSF_CB[ 1 ] = &SKP_Silk_NLSF_CB1_16; + } + /* Reset part of the decoder state */ + SKP_memset( psDec->sLPC_Q14, 0, MAX_LPC_ORDER * sizeof( SKP_int32 ) ); + SKP_memset( psDec->outBuf, 0, MAX_FRAME_LENGTH * sizeof( SKP_int16 ) ); + SKP_memset( psDec->prevNLSF_Q15, 0, MAX_LPC_ORDER * sizeof( SKP_int ) ); + + psDec->lagPrev = 100; + psDec->LastGainIndex = 1; + psDec->prev_sigtype = 0; + psDec->first_frame_after_reset = 1; + + if( fs_kHz == 24 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_24; + psDec->HP_B = SKP_Silk_Dec_B_HP_24; + } else if( fs_kHz == 16 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_16; + psDec->HP_B = SKP_Silk_Dec_B_HP_16; + } else if( fs_kHz == 12 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_12; + psDec->HP_B = SKP_Silk_Dec_B_HP_12; + } else if( fs_kHz == 8 ) { + psDec->HP_A = SKP_Silk_Dec_A_HP_8; + psDec->HP_B = SKP_Silk_Dec_B_HP_8; + } else { + /* unsupported sampling rate */ + SKP_assert( 0 ); + } + } + + /* Check that settings are valid */ + SKP_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); +} + diff --git a/pkg/silk/csilk/SKP_Silk_define.h b/pkg/silk/csilk/SKP_Silk_define.h new file mode 100644 index 0000000..43e8e68 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_define.h @@ -0,0 +1,306 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_DEFINE_H +#define SKP_SILK_DEFINE_H + +#include "SKP_Silk_errors.h" +#include "SKP_Silk_typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +#define MAX_FRAMES_PER_PACKET 5 + + + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 100000 + +/* Transition bitrates between modes */ +#define SWB2WB_BITRATE_BPS 25000 +#define WB2SWB_BITRATE_BPS 30000 +#define WB2MB_BITRATE_BPS 14000 +#define MB2WB_BITRATE_BPS 18000 +#define MB2NB_BITRATE_BPS 10000 +#define NB2MB_BITRATE_BPS 14000 + +/* Integration/hysteresis threshold for lowering internal sample frequency */ +/* 30000000 -> 6 sec if bitrate is 5000 bps below limit; 3 sec if bitrate is 10000 bps below limit */ +#define ACCUM_BITS_DIFF_THRESHOLD 30000000 +#define TARGET_RATE_TAB_SZ 8 + +/* DTX settings */ +#define NO_SPEECH_FRAMES_BEFORE_DTX 5 /* eq 100 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ + +#define USE_LBRR 1 + +/* Amount of concecutive no FEC packets before telling JB */ +#define NO_LBRR_THRES 10 + +/* Maximum delay between real packet and LBRR packet */ +#define MAX_LBRR_DELAY 2 +#define LBRR_IDX_MASK 1 + +#define INBAND_FEC_MIN_RATE_BPS 18000 /* Dont use inband FEC below this total target rate */ +#define LBRR_LOSS_THRES 1 /* Start adding LBRR at this loss rate */ + +/* LBRR usage defines */ +#define SKP_SILK_NO_LBRR 0 /* No LBRR information for this packet */ +#define SKP_SILK_ADD_LBRR_TO_PLUS1 1 /* Add LBRR for this packet to packet n + 1 */ +#define SKP_SILK_ADD_LBRR_TO_PLUS2 2 /* Add LBRR for this packet to packet n + 2 */ + +/* Frame termination indicator defines */ +#define SKP_SILK_LAST_FRAME 0 /* Last frames in packet */ +#define SKP_SILK_MORE_FRAMES 1 /* More frames to follow this one */ +#define SKP_SILK_LBRR_VER1 2 /* LBRR information from packet n - 1 */ +#define SKP_SILK_LBRR_VER2 3 /* LBRR information from packet n - 2 */ +#define SKP_SILK_EXT_LAYER 4 /* Extension layers added */ + +/* Number of Second order Sections for SWB detection HP filter */ +#define NB_SOS 3 +#define HP_8_KHZ_THRES 10 /* average energy per sample, above 8 kHz */ +#define CONCEC_SWB_SMPLS_THRES 480 * 15 /* 300 ms */ +#define WB_DETECT_ACTIVE_SPEECH_MS_THRES 15000 /* ms of active speech needed for WB detection */ + +/* Low complexity setting */ +#define LOW_COMPLEXITY_ONLY 0 + +/* Activate bandwidth transition filtering for mode switching */ +#define SWITCH_TRANSITION_FILTERING 1 + +/* Decoder Parameters */ +#define DEC_HP_ORDER 2 + +/* Maximum sampling frequency, should be 16 for some embedded platforms */ +#define MAX_FS_KHZ 24 +#define MAX_API_FS_KHZ 48 + +/* Signal Types used by silk */ +#define SIG_TYPE_VOICED 0 +#define SIG_TYPE_UNVOICED 1 + +/* VAD Types used by silk */ +#define NO_VOICE_ACTIVITY 0 +#define VOICE_ACTIVITY 1 + +/* Number of samples per frame */ +#define FRAME_LENGTH_MS 20 +#define MAX_FRAME_LENGTH ( FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +#define PITCH_EST_COMPLEXITY_HC_MODE SKP_Silk_PITCH_EST_MAX_COMPLEX +#define PITCH_EST_COMPLEXITY_MC_MODE SKP_Silk_PITCH_EST_MID_COMPLEX +#define PITCH_EST_COMPLEXITY_LC_MODE SKP_Silk_PITCH_EST_MIN_COMPLEX + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Max length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* Max number of bytes in payload output buffer (may contain multiple frames) */ +#define MAX_ARITHM_BYTES 1024 + +#define RANGE_CODER_WRITE_BEYOND_BUFFER -1 +#define RANGE_CODER_CDF_OUT_OF_RANGE -2 +#define RANGE_CODER_NORMALIZATION_FAILED -3 +#define RANGE_CODER_ZERO_INTERVAL_WIDTH -4 +#define RANGE_CODER_DECODER_CHECK_FAILED -5 +#define RANGE_CODER_READ_BEYOND_BUFFER -6 +#define RANGE_CODER_ILLEGAL_SAMPLING_RATE -7 +#define RANGE_CODER_DEC_PAYLOAD_TOO_LONG -8 + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 6 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 86 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 40 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 256 + +/* Maximum numbers of iterations used to stabilize a LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 20 + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Number of subframes */ +#define NB_SUBFR 4 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 16 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK (LTP_BUF_LENGTH - 1) + +#define DECISION_DELAY 32 +#define DECISION_DELAY_MASK (DECISION_DELAY - 1) + +/* number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define MAX_NB_SHELL_BLOCKS (MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH) + +/* number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* maximum sum of pulses per shell coding frame */ +#define MAX_PULSES 18 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +#if( MAX_LPC_ORDER > DECISION_DELAY ) +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER +#else +# define NSQ_LPC_BUF_LENGTH DECISION_DELAY +#endif + +/***********************/ +/* High pass filtering */ +/***********************/ +#define HIGH_PASS_INPUT 1 + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES (1 << VAD_INTERNAL_SUBFRAMES_LOG2) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/******************/ +/* NLSF quantizer */ +/******************/ +# define NLSF_MSVQ_MAX_CB_STAGES 10 /* Update manually when changing codebooks */ +# define NLSF_MSVQ_MAX_VECTORS_IN_STAGE 128 /* Update manually when changing codebooks */ +# define NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END 16 /* Update manually when changing codebooks */ + +#define NLSF_MSVQ_FLUCTUATION_REDUCTION 1 +#define MAX_NLSF_MSVQ_SURVIVORS 16 +#define MAX_NLSF_MSVQ_SURVIVORS_LC_MODE 2 +#define MAX_NLSF_MSVQ_SURVIVORS_MC_MODE 4 + +/* Based on above defines, calculate how much memory is necessary to allocate */ +#if( NLSF_MSVQ_MAX_VECTORS_IN_STAGE > ( MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END ) ) +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE NLSF_MSVQ_MAX_VECTORS_IN_STAGE +#else +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END +#endif + +#if( NLSF_MSVQ_MAX_VECTORS_IN_STAGE > ( MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END ) ) +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED NLSF_MSVQ_MAX_VECTORS_IN_STAGE +#else +# define NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED MAX_NLSF_MSVQ_SURVIVORS * NLSF_MSVQ_MAX_VECTORS_IN_STAGE_TWO_TO_END +#endif + +#define NLSF_MSVQ_SURV_MAX_REL_RD 0.1f /* Must be < 0.5 */ + +/* Transition filtering for mode switching */ +#if SWITCH_TRANSITION_FILTERING +# define TRANSITION_TIME_UP_MS 5120 // 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4) +# define TRANSITION_TIME_DOWN_MS 2560 // 2560 = 32 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 32*(20*4) +# define TRANSITION_NB 3 /* Hardcoded in tables */ +# define TRANSITION_NA 2 /* Hardcoded in tables */ +# define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +# define TRANSITION_FRAMES_UP ( TRANSITION_TIME_UP_MS / FRAME_LENGTH_MS ) +# define TRANSITION_FRAMES_DOWN ( TRANSITION_TIME_DOWN_MS / FRAME_LENGTH_MS ) +# define TRANSITION_INT_STEPS_UP ( TRANSITION_FRAMES_UP / ( TRANSITION_INT_NUM - 1 ) ) +# define TRANSITION_INT_STEPS_DOWN ( TRANSITION_FRAMES_DOWN / ( TRANSITION_INT_NUM - 1 ) ) +#endif + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) *(Matrix_base_adr + ((row)*(N)+(column))) +#define matrix_adr(Matrix_base_adr, row, column, N) (Matrix_base_adr + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) *(Matrix_base_adr + ((row)+(M)*(column))) +#endif +#define matrix_c_adr(Matrix_base_adr, row, column, M) (Matrix_base_adr + ((row)+(M)*(column))) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_detect_SWB_input.c b/pkg/silk/csilk/SKP_Silk_detect_SWB_input.c new file mode 100644 index 0000000..eb3ee05 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_detect_SWB_input.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* + * Detect SWB input by measuring energy above 8 kHz. + */ + +#include "SKP_Silk_main.h" + +void SKP_Silk_detect_SWB_input( + SKP_Silk_detect_SWB_state *psSWBdetect, /* (I/O) encoder state */ + const SKP_int16 samplesIn[], /* (I) input to encoder */ + SKP_int nSamplesIn /* (I) length of input */ +) +{ + SKP_int HP_8_kHz_len, i, shift; + SKP_int16 in_HP_8_kHz[ MAX_FRAME_LENGTH ]; + SKP_int32 energy_32; + + /* High pass filter with cutoff at 8 khz */ + HP_8_kHz_len = SKP_min_int( nSamplesIn, MAX_FRAME_LENGTH ); + HP_8_kHz_len = SKP_max_int( HP_8_kHz_len, 0 ); + + /* Cutoff around 9 khz */ + /* A = conv(conv([8192,14613, 6868], [8192,12883, 7337]), [8192,11586, 7911]); */ + /* B = conv(conv([575, -948, 575], [575, -221, 575]), [575, 104, 575]); */ + SKP_Silk_biquad( samplesIn, SKP_Silk_SWB_detect_B_HP_Q13[ 0 ], SKP_Silk_SWB_detect_A_HP_Q13[ 0 ], + psSWBdetect->S_HP_8_kHz[ 0 ], in_HP_8_kHz, HP_8_kHz_len ); + for( i = 1; i < NB_SOS; i++ ) { + SKP_Silk_biquad( in_HP_8_kHz, SKP_Silk_SWB_detect_B_HP_Q13[ i ], SKP_Silk_SWB_detect_A_HP_Q13[ i ], + psSWBdetect->S_HP_8_kHz[ i ], in_HP_8_kHz, HP_8_kHz_len ); + } + + /* Calculate energy in HP signal */ + SKP_Silk_sum_sqr_shift( &energy_32, &shift, in_HP_8_kHz, HP_8_kHz_len ); + + /* Count concecutive samples above threshold, after adjusting threshold for number of input samples and shift */ + if( energy_32 > SKP_RSHIFT( SKP_SMULBB( HP_8_KHZ_THRES, HP_8_kHz_len ), shift ) ) { + psSWBdetect->ConsecSmplsAboveThres += nSamplesIn; + if( psSWBdetect->ConsecSmplsAboveThres > CONCEC_SWB_SMPLS_THRES ) { + psSWBdetect->SWB_detected = 1; + } + } else { + psSWBdetect->ConsecSmplsAboveThres -= nSamplesIn; + psSWBdetect->ConsecSmplsAboveThres = SKP_max( psSWBdetect->ConsecSmplsAboveThres, 0 ); + } + + /* If sufficient speech activity and no SWB detected, we detect the signal as being WB */ + if( ( psSWBdetect->ActiveSpeech_ms > WB_DETECT_ACTIVE_SPEECH_MS_THRES ) && ( psSWBdetect->SWB_detected == 0 ) ) { + psSWBdetect->WB_detected = 1; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_div_oabi.c b/pkg/silk/csilk/SKP_Silk_div_oabi.c new file mode 100644 index 0000000..327dcfa --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_div_oabi.c @@ -0,0 +1,35 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_typedef.h" + +SKP_int32 SKP_DIV32_arm( SKP_int32 a32, SKP_int32 b32 ) { + return ( ( SKP_int32 )( ( a32 ) / ( b32 ) ) ); +} + + + diff --git a/pkg/silk/csilk/SKP_Silk_enc_API.c b/pkg/silk/csilk/SKP_Silk_enc_API.c new file mode 100644 index 0000000..63657ab --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_enc_API.c @@ -0,0 +1,247 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + + +#include "SKP_Silk_define.h" +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_SDK_API.h" +#include "SKP_Silk_control.h" +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_structs.h" +#define SKP_Silk_EncodeControlStruct SKP_SILK_SDK_EncControlStruct + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +SKP_int SKP_Silk_SDK_Get_Encoder_Size( SKP_int32 *encSizeBytes ) +{ + SKP_int ret = 0; + + *encSizeBytes = sizeof( SKP_Silk_encoder_state_FIX ); + + return ret; +} + + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +SKP_int SKP_Silk_SDK_QueryEncoder( + const void *encState, /* I: State Vector */ + SKP_Silk_EncodeControlStruct *encStatus /* O: Control Structure */ +) +{ + SKP_Silk_encoder_state_FIX *psEnc; + SKP_int ret = 0; + + psEnc = ( SKP_Silk_encoder_state_FIX* )encState; + + encStatus->API_sampleRate = psEnc->sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = SKP_SMULBB( psEnc->sCmn.maxInternal_fs_kHz, 1000 ); + encStatus->packetSize = ( SKP_int )SKP_DIV32_16( psEnc->sCmn.API_fs_Hz * psEnc->sCmn.PacketSize_ms, 1000 ); /* convert samples -> ms */ + encStatus->bitRate = psEnc->sCmn.TargetRate_bps; + encStatus->packetLossPercentage = psEnc->sCmn.PacketLoss_perc; + encStatus->complexity = psEnc->sCmn.Complexity; + encStatus->useInBandFEC = psEnc->sCmn.useInBandFEC; + encStatus->useDTX = psEnc->sCmn.useDTX; + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +SKP_int SKP_Silk_SDK_InitEncoder( + void *encState, /* I/O: State */ + SKP_Silk_EncodeControlStruct *encStatus /* O: Control structure */ +) +{ + SKP_Silk_encoder_state_FIX *psEnc; + SKP_int ret = 0; + + + psEnc = ( SKP_Silk_encoder_state_FIX* )encState; + + /* Reset Encoder */ + if( ret += SKP_Silk_init_encoder_FIX( psEnc ) ) { + SKP_assert( 0 ); + } + + /* Read control structure */ + if( ret += SKP_Silk_SDK_QueryEncoder( encState, encStatus ) ) { + SKP_assert( 0 ); + } + + + return ret; +} + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +SKP_int SKP_Silk_SDK_Encode( + void *encState, /* I/O: State */ + const SKP_Silk_EncodeControlStruct *encControl, /* I: Control structure */ + const SKP_int16 *samplesIn, /* I: Speech sample input vector */ + SKP_int nSamplesIn, /* I: Number of samples in input vector */ + SKP_uint8 *outData, /* O: Encoded output vector */ + SKP_int16 *nBytesOut /* I/O: Number of bytes in outData (input: Max bytes) */ +) +{ + SKP_int max_internal_fs_kHz, PacketSize_ms, PacketLoss_perc, UseInBandFEC, UseDTX, ret = 0; + SKP_int nSamplesToBuffer, Complexity, input_10ms, nSamplesFromInput = 0; + SKP_int32 TargetRate_bps, API_fs_Hz; + SKP_int16 MaxBytesOut; + SKP_Silk_encoder_state_FIX *psEnc = ( SKP_Silk_encoder_state_FIX* )encState; + + SKP_assert( encControl != NULL ); + + /* Check sampling frequency first, to avoid divide by zero later */ + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) && + ( encControl->maxInternalSampleRate != 24000 ) ) ) { + ret = SKP_SILK_ENC_FS_NOT_SUPPORTED; + SKP_assert( 0 ); + return( ret ); + } + + /* Set encoder parameters from control structure */ + API_fs_Hz = encControl->API_sampleRate; + max_internal_fs_kHz = (SKP_int)( encControl->maxInternalSampleRate >> 10 ) + 1; /* convert Hz -> kHz */ + PacketSize_ms = SKP_DIV32( 1000 * (SKP_int)encControl->packetSize, API_fs_Hz ); + TargetRate_bps = encControl->bitRate; + PacketLoss_perc = encControl->packetLossPercentage; + UseInBandFEC = encControl->useInBandFEC; + Complexity = encControl->complexity; + UseDTX = encControl->useDTX; + + /* Save values in state */ + psEnc->sCmn.API_fs_Hz = API_fs_Hz; + psEnc->sCmn.maxInternal_fs_kHz = max_internal_fs_kHz; + psEnc->sCmn.useInBandFEC = UseInBandFEC; + + /* Only accept input lengths that are a multiple of 10 ms */ + input_10ms = SKP_DIV32( 100 * nSamplesIn, API_fs_Hz ); + if( input_10ms * API_fs_Hz != 100 * nSamplesIn || nSamplesIn < 0 ) { + ret = SKP_SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + SKP_assert( 0 ); + return( ret ); + } + + TargetRate_bps = SKP_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS ); + if( ( ret = SKP_Silk_control_encoder_FIX( psEnc, PacketSize_ms, TargetRate_bps, + PacketLoss_perc, UseDTX, Complexity) ) != 0 ) { + SKP_assert( 0 ); + return( ret ); + } + + /* Make sure no more than one packet can be produced */ + if( 1000 * (SKP_int32)nSamplesIn > psEnc->sCmn.PacketSize_ms * API_fs_Hz ) { + ret = SKP_SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + SKP_assert( 0 ); + return( ret ); + } + +#if MAX_FS_KHZ > 16 + /* Detect energy above 8 kHz */ + if( SKP_min( API_fs_Hz, 1000 * max_internal_fs_kHz ) == 24000 && + psEnc->sCmn.sSWBdetect.SWB_detected == 0 && + psEnc->sCmn.sSWBdetect.WB_detected == 0 ) { + SKP_Silk_detect_SWB_input( &psEnc->sCmn.sSWBdetect, samplesIn, ( SKP_int )nSamplesIn ); + } +#endif + + /* Input buffering/resampling and encoding */ + MaxBytesOut = 0; /* return 0 output bytes if no encoder called */ + while( 1 ) { + nSamplesToBuffer = psEnc->sCmn.frame_length - psEnc->sCmn.inputBufIx; + if( API_fs_Hz == SKP_SMULBB( 1000, psEnc->sCmn.fs_kHz ) ) { + nSamplesToBuffer = SKP_min_int( nSamplesToBuffer, nSamplesIn ); + nSamplesFromInput = nSamplesToBuffer; + /* Copy to buffer */ + SKP_memcpy( &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput * sizeof( SKP_int16 ) ); + } else { + nSamplesToBuffer = SKP_min( nSamplesToBuffer, 10 * input_10ms * psEnc->sCmn.fs_kHz ); + nSamplesFromInput = SKP_DIV32_16( nSamplesToBuffer * API_fs_Hz, psEnc->sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + ret += SKP_Silk_resampler( &psEnc->sCmn.resampler_state, + &psEnc->sCmn.inputBuf[ psEnc->sCmn.inputBufIx ], samplesIn, nSamplesFromInput ); + } + samplesIn += nSamplesFromInput; + nSamplesIn -= nSamplesFromInput; + psEnc->sCmn.inputBufIx += nSamplesToBuffer; + + /* Silk encoder */ + if( psEnc->sCmn.inputBufIx >= psEnc->sCmn.frame_length ) { + SKP_assert( psEnc->sCmn.inputBufIx == psEnc->sCmn.frame_length ); + + /* Enough data in input buffer, so encode */ + if( MaxBytesOut == 0 ) { + /* No payload obtained so far */ + MaxBytesOut = *nBytesOut; + if( ( ret = SKP_Silk_encode_frame_FIX( psEnc, outData, &MaxBytesOut, psEnc->sCmn.inputBuf ) ) != 0 ) { + SKP_assert( 0 ); + } + } else { + /* outData already contains a payload */ + if( ( ret = SKP_Silk_encode_frame_FIX( psEnc, outData, nBytesOut, psEnc->sCmn.inputBuf ) ) != 0 ) { + SKP_assert( 0 ); + } + /* Check that no second payload was created */ + SKP_assert( *nBytesOut == 0 ); + } + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.controlled_since_last_payload = 0; + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + } + + *nBytesOut = MaxBytesOut; + if( psEnc->sCmn.useDTX && psEnc->sCmn.inDTX ) { + /* DTX simulation */ + *nBytesOut = 0; + } + + + + return ret; +} + + diff --git a/pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c b/pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c new file mode 100644 index 0000000..c108289 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c @@ -0,0 +1,413 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/****************/ +/* Encode frame */ +/****************/ +SKP_int SKP_Silk_encode_frame_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes */ + /* input: max length; output: used */ + const SKP_int16 *pIn /* I Pointer to input speech frame */ +) +{ + SKP_Silk_encoder_control_FIX sEncCtrl; + SKP_int nBytes, ret = 0; + SKP_int16 *x_frame, *res_pitch_frame; + SKP_int16 xfw[ MAX_FRAME_LENGTH ]; + SKP_int16 pIn_HP[ MAX_FRAME_LENGTH ]; + SKP_int16 res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + SKP_int LBRR_idx, frame_terminator, SNR_dB_Q7; + const SKP_uint16 *FrameTermination_CDF; + /* Low bitrate redundancy parameters */ + SKP_uint8 LBRRpayload[ MAX_ARITHM_BYTES ]; + SKP_int16 nBytesLBRR; + + + sEncCtrl.sCmn.Seed = psEnc->sCmn.frameCounter++ & 3; + /**************************************************************/ + /* Setup Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + x_frame = psEnc->x_buf + psEnc->sCmn.frame_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.frame_length; /* start of pitch LPC residual frame */ + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + ret = SKP_Silk_VAD_GetSA_Q8( &psEnc->sCmn.sVAD, &psEnc->speech_activity_Q8, &SNR_dB_Q7, + sEncCtrl.input_quality_bands_Q15, &sEncCtrl.input_tilt_Q15, + pIn,psEnc->sCmn.frame_length ); + + /*******************************************/ + /* High-pass filtering of the input signal */ + /*******************************************/ +#if HIGH_PASS_INPUT + /* Variable high-pass filter */ + SKP_Silk_HP_variable_cutoff_FIX( psEnc, &sEncCtrl, pIn_HP, pIn ); +#else + SKP_memcpy( pIn_HP, pIn, psEnc->sCmn.frame_length * sizeof( SKP_int16 ) ); +#endif + +#if SWITCH_TRANSITION_FILTERING + /* Ensure smooth bandwidth transitions */ + SKP_Silk_LP_variable_cutoff( &psEnc->sCmn.sLP, x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, pIn_HP, psEnc->sCmn.frame_length ); +#else + SKP_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, pIn_HP,psEnc->sCmn.frame_length * sizeof( SKP_int16 ) ); +#endif + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + SKP_Silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + SKP_Silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + SKP_Silk_prefilter_FIX( psEnc, &sEncCtrl, xfw, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + SKP_Silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch ); + + /****************************************/ + /* Process gains */ + /****************************************/ + SKP_Silk_process_gains_FIX( psEnc, &sEncCtrl ); + + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + nBytesLBRR = MAX_ARITHM_BYTES; + SKP_Silk_LBRR_encode_FIX( psEnc, &sEncCtrl, LBRRpayload, &nBytesLBRR, xfw ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &sEncCtrl.sCmn, &psEnc->sCmn.sNSQ, xfw, + psEnc->sCmn.q, sEncCtrl.sCmn.NLSFInterpCoef_Q2, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.Lambda_Q10, + sEncCtrl.LTP_scale_Q14 ); + } else { + SKP_Silk_NSQ( &psEnc->sCmn, &sEncCtrl.sCmn, &psEnc->sCmn.sNSQ, xfw, + psEnc->sCmn.q, sEncCtrl.sCmn.NLSFInterpCoef_Q2, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.Lambda_Q10, + sEncCtrl.LTP_scale_Q14 ); + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->speech_activity_Q8 < SKP_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + psEnc->sCmn.vadFlag = NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter > NO_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 1; + } + if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NO_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NO_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.vadFlag = VOICE_ACTIVITY; + } + + /****************************************/ + /* Initialize range coder */ + /****************************************/ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + SKP_Silk_range_enc_init( &psEnc->sCmn.sRC ); + psEnc->sCmn.nBytesInPayloadBuf = 0; + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + SKP_Silk_encode_parameters( &psEnc->sCmn, &sEncCtrl.sCmn, &psEnc->sCmn.sRC, psEnc->sCmn.q ); + FrameTermination_CDF = SKP_Silk_FrameTermination_CDF; + + /****************************************/ + /* Update Buffers and State */ + /****************************************/ + /* Update input buffer */ + SKP_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.frame_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( SKP_int16 ) ); + + /* Parameters needed for next frame */ + psEnc->sCmn.prev_sigtype = sEncCtrl.sCmn.sigtype; + psEnc->sCmn.prevLag = sEncCtrl.sCmn.pitchL[ NB_SUBFR - 1]; + psEnc->sCmn.first_frame_after_reset = 0; + + if( psEnc->sCmn.sRC.error ) { + /* Encoder returned error: clear payload buffer */ + psEnc->sCmn.nFramesInPayloadBuf = 0; + } else { + psEnc->sCmn.nFramesInPayloadBuf++; + } + + /****************************************/ + /* Finalize payload and copy to output */ + /****************************************/ + if( psEnc->sCmn.nFramesInPayloadBuf * FRAME_LENGTH_MS >= psEnc->sCmn.PacketSize_ms ) { + + LBRR_idx = ( psEnc->sCmn.oldest_LBRR_idx + 1 ) & LBRR_IDX_MASK; + + /* Check if FEC information should be added */ + frame_terminator = SKP_SILK_LAST_FRAME; + if( psEnc->sCmn.LBRR_buffer[ LBRR_idx ].usage == SKP_SILK_ADD_LBRR_TO_PLUS1 ) { + frame_terminator = SKP_SILK_LBRR_VER1; + } + if( psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].usage == SKP_SILK_ADD_LBRR_TO_PLUS2 ) { + frame_terminator = SKP_SILK_LBRR_VER2; + LBRR_idx = psEnc->sCmn.oldest_LBRR_idx; + } + + /* Add the frame termination info to stream */ + SKP_Silk_range_encoder( &psEnc->sCmn.sRC, frame_terminator, FrameTermination_CDF ); + + /* Payload length so far */ + SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC, &nBytes ); + + /* Check that there is enough space in external output buffer, and move data */ + if( *pnBytesOut >= nBytes ) { + SKP_Silk_range_enc_wrap_up( &psEnc->sCmn.sRC ); + SKP_memcpy( pCode, psEnc->sCmn.sRC.buffer, nBytes * sizeof( SKP_uint8 ) ); + + if( frame_terminator > SKP_SILK_MORE_FRAMES && + *pnBytesOut >= nBytes + psEnc->sCmn.LBRR_buffer[ LBRR_idx ].nBytes ) { + /* Get old packet and add to payload. */ + SKP_memcpy( &pCode[ nBytes ], + psEnc->sCmn.LBRR_buffer[ LBRR_idx ].payload, + psEnc->sCmn.LBRR_buffer[ LBRR_idx ].nBytes * sizeof( SKP_uint8 ) ); + nBytes += psEnc->sCmn.LBRR_buffer[ LBRR_idx ].nBytes; + } + + *pnBytesOut = nBytes; + + /* Update FEC buffer */ + SKP_memcpy( psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].payload, LBRRpayload, + nBytesLBRR * sizeof( SKP_uint8 ) ); + psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].nBytes = nBytesLBRR; + /* The line below describes how FEC should be used */ + psEnc->sCmn.LBRR_buffer[ psEnc->sCmn.oldest_LBRR_idx ].usage = sEncCtrl.sCmn.LBRR_usage; + psEnc->sCmn.oldest_LBRR_idx = ( psEnc->sCmn.oldest_LBRR_idx + 1 ) & LBRR_IDX_MASK; + + } else { + /* Not enough space: Payload will be discarded */ + *pnBytesOut = 0; + nBytes = 0; + ret = SKP_SILK_ENC_PAYLOAD_BUF_TOO_SHORT; + } + + /* Reset the number of frames in payload buffer */ + psEnc->sCmn.nFramesInPayloadBuf = 0; + } else { + /* No payload this time */ + *pnBytesOut = 0; + + /* Encode that more frames follows */ + frame_terminator = SKP_SILK_MORE_FRAMES; + SKP_Silk_range_encoder( &psEnc->sCmn.sRC, frame_terminator, FrameTermination_CDF ); + + /* Payload length so far */ + SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC, &nBytes ); + + } + + /* Check for arithmetic coder errors */ + if( psEnc->sCmn.sRC.error ) { + ret = SKP_SILK_ENC_INTERNAL_ERROR; + } + + /* Simulate number of ms buffered in channel because of exceeding TargetRate */ + SKP_assert( ( 8 * 1000 * ( (SKP_int64)nBytes - (SKP_int64)psEnc->sCmn.nBytesInPayloadBuf ) ) == + SKP_SAT32( 8 * 1000 * ( (SKP_int64)nBytes - (SKP_int64)psEnc->sCmn.nBytesInPayloadBuf ) ) ); + SKP_assert( psEnc->sCmn.TargetRate_bps > 0 ); + psEnc->BufferedInChannel_ms += SKP_DIV32( 8 * 1000 * ( nBytes - psEnc->sCmn.nBytesInPayloadBuf ), psEnc->sCmn.TargetRate_bps ); + psEnc->BufferedInChannel_ms -= FRAME_LENGTH_MS; + psEnc->BufferedInChannel_ms = SKP_LIMIT_int( psEnc->BufferedInChannel_ms, 0, 100 ); + psEnc->sCmn.nBytesInPayloadBuf = nBytes; + + if( psEnc->speech_activity_Q8 > SKP_FIX_CONST( WB_DETECT_ACTIVE_SPEECH_LEVEL_THRES, 8 ) ) { + psEnc->sCmn.sSWBdetect.ActiveSpeech_ms = SKP_ADD_POS_SAT32( psEnc->sCmn.sSWBdetect.ActiveSpeech_ms, FRAME_LENGTH_MS ); + } + + + return( ret ); +} + +/* Low BitRate Redundancy encoding functionality. Reuse all parameters but encode residual with lower bitrate */ +void SKP_Silk_LBRR_encode_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk encoder control struct */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes */ + SKP_int16 xfw[] /* I Input signal */ +) +{ + SKP_int TempGainsIndices[ NB_SUBFR ], frame_terminator; + SKP_int nBytes, nFramesInPayloadBuf; + SKP_int32 TempGains_Q16[ NB_SUBFR ]; + SKP_int typeOffset, LTP_scaleIndex, Rate_only_parameters = 0; + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + SKP_Silk_LBRR_ctrl_FIX( psEnc, &psEncCtrl->sCmn ); + + if( psEnc->sCmn.LBRR_enabled ) { + /* Save original gains */ + SKP_memcpy( TempGainsIndices, psEncCtrl->sCmn.GainsIndices, NB_SUBFR * sizeof( SKP_int ) ); + SKP_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, NB_SUBFR * sizeof( SKP_int32 ) ); + + typeOffset = psEnc->sCmn.typeOffsetPrev; // Temp save as cannot be overwritten + LTP_scaleIndex = psEncCtrl->sCmn.LTP_scaleIndex; + + /* Set max rate where quant signal is encoded */ + if( psEnc->sCmn.fs_kHz == 8 ) { + Rate_only_parameters = 13500; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + Rate_only_parameters = 15500; + } else if( psEnc->sCmn.fs_kHz == 16 ) { + Rate_only_parameters = 17500; + } else if( psEnc->sCmn.fs_kHz == 24 ) { + Rate_only_parameters = 19500; + } else { + SKP_assert( 0 ); + } + + if( psEnc->sCmn.Complexity > 0 && psEnc->sCmn.TargetRate_bps > Rate_only_parameters ) { + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + /* First frame in packet; copy everything */ + SKP_memcpy( &psEnc->sCmn.sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( SKP_Silk_nsq_state ) ); + + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + /* Increase Gains to get target LBRR rate */ + psEncCtrl->sCmn.GainsIndices[ 0 ] = psEncCtrl->sCmn.GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psEncCtrl->sCmn.GainsIndices[ 0 ] = SKP_LIMIT_int( psEncCtrl->sCmn.GainsIndices[ 0 ], 0, N_LEVELS_QGAIN - 1 ); + } + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + SKP_Silk_gains_dequant( psEncCtrl->Gains_Q16, psEncCtrl->sCmn.GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, psEnc->sCmn.nFramesInPayloadBuf ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ_LBRR, xfw, psEnc->sCmn.q_LBRR, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } else { + SKP_Silk_NSQ( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ_LBRR, xfw, psEnc->sCmn.q_LBRR, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } + } else { + SKP_memset( psEnc->sCmn.q_LBRR, 0, psEnc->sCmn.frame_length * sizeof( SKP_int8 ) ); + psEncCtrl->sCmn.LTP_scaleIndex = 0; + } + /****************************************/ + /* Initialize arithmetic coder */ + /****************************************/ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + SKP_Silk_range_enc_init( &psEnc->sCmn.sRC_LBRR ); + psEnc->sCmn.nBytesInPayloadBuf = 0; + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + SKP_Silk_encode_parameters( &psEnc->sCmn, &psEncCtrl->sCmn, + &psEnc->sCmn.sRC_LBRR, psEnc->sCmn.q_LBRR ); + + if( psEnc->sCmn.sRC_LBRR.error ) { + /* Encoder returned error: clear payload buffer */ + nFramesInPayloadBuf = 0; + } else { + nFramesInPayloadBuf = psEnc->sCmn.nFramesInPayloadBuf + 1; + } + + /****************************************/ + /* Finalize payload and copy to output */ + /****************************************/ + if( SKP_SMULBB( nFramesInPayloadBuf, FRAME_LENGTH_MS ) >= psEnc->sCmn.PacketSize_ms ) { + + /* Check if FEC information should be added */ + frame_terminator = SKP_SILK_LAST_FRAME; + + /* Add the frame termination info to stream */ + SKP_Silk_range_encoder( &psEnc->sCmn.sRC_LBRR, frame_terminator, SKP_Silk_FrameTermination_CDF ); + + /* Payload length so far */ + SKP_Silk_range_coder_get_length( &psEnc->sCmn.sRC_LBRR, &nBytes ); + + /* Check that there is enough space in external output buffer and move data */ + if( *pnBytesOut >= nBytes ) { + SKP_Silk_range_enc_wrap_up( &psEnc->sCmn.sRC_LBRR ); + SKP_memcpy( pCode, psEnc->sCmn.sRC_LBRR.buffer, nBytes * sizeof( SKP_uint8 ) ); + + *pnBytesOut = nBytes; + } else { + /* Not enough space: payload will be discarded */ + *pnBytesOut = 0; + SKP_assert( 0 ); + } + } else { + /* No payload this time */ + *pnBytesOut = 0; + + /* Encode that more frames follows */ + frame_terminator = SKP_SILK_MORE_FRAMES; + SKP_Silk_range_encoder( &psEnc->sCmn.sRC_LBRR, frame_terminator, SKP_Silk_FrameTermination_CDF ); + } + + /* Restore original Gains */ + SKP_memcpy( psEncCtrl->sCmn.GainsIndices, TempGainsIndices, NB_SUBFR * sizeof( SKP_int ) ); + SKP_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, NB_SUBFR * sizeof( SKP_int32 ) ); + + /* Restore LTP scale index and typeoffset */ + psEncCtrl->sCmn.LTP_scaleIndex = LTP_scaleIndex; + psEnc->sCmn.typeOffsetPrev = typeOffset; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_encode_parameters.c b/pkg/silk/csilk/SKP_Silk_encode_parameters.c new file mode 100644 index 0000000..be50e01 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_encode_parameters.c @@ -0,0 +1,162 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/*******************************************/ +/* Encode parameters to create the payload */ +/*******************************************/ +void SKP_Silk_encode_parameters( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder state */ + SKP_Silk_encoder_control *psEncCtrlC, /* I/O Encoder control */ + SKP_Silk_range_coder_state *psRC, /* I/O Range encoder state */ + const SKP_int8 *q /* I Quantization indices */ +) +{ + SKP_int i, k, typeOffset; + const SKP_Silk_NLSF_CB_struct *psNLSF_CB; + + + /************************/ + /* Encode sampling rate */ + /************************/ + /* only done for first frame in packet */ + if( psEncC->nFramesInPayloadBuf == 0 ) { + /* get sampling rate index */ + for( i = 0; i < 3; i++ ) { + if( SKP_Silk_SamplingRates_table[ i ] == psEncC->fs_kHz ) { + break; + } + } + SKP_Silk_range_encoder( psRC, i, SKP_Silk_SamplingRates_CDF ); + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psEncCtrlC->sigtype + psEncCtrlC->QuantOffsetType; + if( psEncC->nFramesInPayloadBuf == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_encoder( psRC, typeOffset, SKP_Silk_type_offset_CDF ); + } else { + /* condidtional coding */ + SKP_Silk_range_encoder( psRC, typeOffset, SKP_Silk_type_offset_joint_CDF[ psEncC->typeOffsetPrev ] ); + } + psEncC->typeOffsetPrev = typeOffset; + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( psEncC->nFramesInPayloadBuf == 0 ) { + /* first frame in packet: independent coding */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->GainsIndices[ 0 ], SKP_Silk_gain_CDF[ psEncCtrlC->sigtype ] ); + } else { + /* condidtional coding */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->GainsIndices[ 0 ], SKP_Silk_delta_gain_CDF ); + } + + /* remaining subframes */ + for( i = 1; i < NB_SUBFR; i++ ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->GainsIndices[ i ], SKP_Silk_delta_gain_CDF ); + } + + + /****************/ + /* Encode NLSFs */ + /****************/ + /* Range encoding of the NLSF path */ + psNLSF_CB = psEncC->psNLSF_CB[ psEncCtrlC->sigtype ]; + SKP_Silk_range_encoder_multi( psRC, psEncCtrlC->NLSFIndices, psNLSF_CB->StartPtr, psNLSF_CB->nStages ); + + /* Encode NLSF interpolation factor */ + SKP_assert( psEncC->useInterpolatedNLSFs == 1 || psEncCtrlC->NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + SKP_Silk_range_encoder( psRC, psEncCtrlC->NLSFInterpCoef_Q2, SKP_Silk_NLSF_interpolation_factor_CDF ); + + + if( psEncCtrlC->sigtype == SIG_TYPE_VOICED ) { + /*********************/ + /* Encode pitch lags */ + /*********************/ + + + /* lag index */ + if( psEncC->fs_kHz == 8 ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_NB_CDF ); + } else if( psEncC->fs_kHz == 12 ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_MB_CDF ); + } else if( psEncC->fs_kHz == 16 ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_WB_CDF ); + } else { + SKP_Silk_range_encoder( psRC, psEncCtrlC->lagIndex, SKP_Silk_pitch_lag_SWB_CDF ); + } + + + /* countour index */ + if( psEncC->fs_kHz == 8 ) { + /* Less codevectors used in 8 khz mode */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->contourIndex, SKP_Silk_pitch_contour_NB_CDF ); + } else { + /* Joint for 12, 16, 24 khz */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->contourIndex, SKP_Silk_pitch_contour_CDF ); + } + + /********************/ + /* Encode LTP gains */ + /********************/ + + /* PERIndex value */ + SKP_Silk_range_encoder( psRC, psEncCtrlC->PERIndex, SKP_Silk_LTP_per_index_CDF ); + + /* Codebook Indices */ + for( k = 0; k < NB_SUBFR; k++ ) { + SKP_Silk_range_encoder( psRC, psEncCtrlC->LTPIndex[ k ], SKP_Silk_LTP_gain_CDF_ptrs[ psEncCtrlC->PERIndex ] ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + SKP_Silk_range_encoder( psRC, psEncCtrlC->LTP_scaleIndex, SKP_Silk_LTPscale_CDF ); + } + + + /***************/ + /* Encode seed */ + /***************/ + SKP_Silk_range_encoder( psRC, psEncCtrlC->Seed, SKP_Silk_Seed_CDF ); + + /*********************************************/ + /* Encode quantization indices of excitation */ + /*********************************************/ + SKP_Silk_encode_pulses( psRC, psEncCtrlC->sigtype, psEncCtrlC->QuantOffsetType, q, psEncC->frame_length ); + + + /*********************************************/ + /* Encode VAD flag */ + /*********************************************/ + SKP_Silk_range_encoder( psRC, psEncC->vadFlag, SKP_Silk_vadflag_CDF ); +} diff --git a/pkg/silk/csilk/SKP_Silk_encode_pulses.c b/pkg/silk/csilk/SKP_Silk_encode_pulses.c new file mode 100644 index 0000000..b0ea05e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_encode_pulses.c @@ -0,0 +1,195 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +SKP_INLINE SKP_int combine_and_check( /* return ok */ + SKP_int *pulses_comb, /* O */ + const SKP_int *pulses_in, /* I */ + SKP_int max_pulses, /* I max value for sum of pulses */ + SKP_int len /* I number of output values */ +) +{ + SKP_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 SKP_Silk_encode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int sigtype, /* I Sigtype */ + const SKP_int QuantOffsetType,/* I QuantOffsetType */ + const SKP_int8 q[], /* I quantization indices */ + const SKP_int frame_length /* I Frame length */ +) +{ + SKP_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + SKP_int32 abs_q, minSumBits_Q6, sumBits_Q6; + SKP_int abs_pulses[ MAX_FRAME_LENGTH ]; + SKP_int sum_pulses[ MAX_NB_SHELL_BLOCKS ]; + SKP_int nRshifts[ MAX_NB_SHELL_BLOCKS ]; + SKP_int pulses_comb[ 8 ]; + SKP_int *abs_pulses_ptr; + const SKP_int8 *pulses_ptr; + const SKP_uint16 *cdf_ptr; + const SKP_int16 *nBits_ptr; + + SKP_memset( pulses_comb, 0, 8 * sizeof( SKP_int ) ); // Fixing Valgrind reported problem + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + iter = frame_length / SHELL_CODEC_FRAME_LENGTH; + + /* Take the absolute value of the pulses */ + for( i = 0; i < frame_length; i+=4 ) { + abs_pulses[i+0] = ( SKP_int )SKP_abs( q[ i + 0 ] ); + abs_pulses[i+1] = ( SKP_int )SKP_abs( q[ i + 1 ] ); + abs_pulses[i+2] = ( SKP_int )SKP_abs( q[ i + 2 ] ); + abs_pulses[i+3] = ( SKP_int )SKP_abs( q[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + 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, SKP_Silk_max_pulses_table[ 0 ], 8 ); + + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, SKP_Silk_max_pulses_table[ 1 ], 4 ); + + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, SKP_Silk_max_pulses_table[ 2 ], 2 ); + + /* 8+8 -> 16 */ + sum_pulses[ i ] = pulses_comb[ 0 ] + pulses_comb[ 1 ]; + if( sum_pulses[ i ] > SKP_Silk_max_pulses_table[ 3 ] ) { + scale_down++; + } + + if( scale_down ) { + /* We need to down scale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = SKP_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_Q6 = SKP_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = SKP_Silk_pulses_per_block_BITS_Q6[ k ]; + sumBits_Q6 = SKP_Silk_rate_levels_BITS_Q6[sigtype][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q6 += nBits_ptr[ MAX_PULSES + 1 ]; + } else { + sumBits_Q6 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q6 < minSumBits_Q6 ) { + minSumBits_Q6 = sumBits_Q6; + RateLevelIndex = k; + } + } + SKP_Silk_range_encoder( psRC, RateLevelIndex, SKP_Silk_rate_levels_CDF[ sigtype ] ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = SKP_Silk_pulses_per_block_CDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + SKP_Silk_range_encoder( psRC, sum_pulses[ i ], cdf_ptr ); + } else { + SKP_Silk_range_encoder( psRC, MAX_PULSES + 1, cdf_ptr ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + SKP_Silk_range_encoder( psRC, MAX_PULSES + 1, SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS - 1 ] ); + } + SKP_Silk_range_encoder( psRC, sum_pulses[ i ], SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS - 1 ] ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + SKP_Silk_shell_encoder( psRC, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &q[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (SKP_int8)SKP_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = SKP_RSHIFT( abs_q, j ) & 1; + SKP_Silk_range_encoder( psRC, bit, SKP_Silk_lsb_CDF ); + } + bit = abs_q & 1; + SKP_Silk_range_encoder( psRC, bit, SKP_Silk_lsb_CDF ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + SKP_Silk_encode_signs( psRC, q, frame_length, sigtype, QuantOffsetType, RateLevelIndex ); +} diff --git a/pkg/silk/csilk/SKP_Silk_errors.h b/pkg/silk/csilk/SKP_Silk_errors.h new file mode 100644 index 0000000..ee2a487 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_errors.h @@ -0,0 +1,89 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_ERRORS_H +#define SKP_SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SKP_SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiplum of 10 ms, or length is longer than the packet length */ +#define SKP_SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -1 + +/* Sampling frequency not 8000, 12000, 16000 or 24000 Hertz */ +#define SKP_SILK_ENC_FS_NOT_SUPPORTED -2 + +/* Packet size not 20, 40, 60, 80 or 100 ms */ +#define SKP_SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -3 + +/* Allocated payload buffer too short */ +#define SKP_SILK_ENC_PAYLOAD_BUF_TOO_SHORT -4 + +/* Loss rate not between 0 and 100 percent */ +#define SKP_SILK_ENC_INVALID_LOSS_RATE -5 + +/* Complexity setting not valid, use 0, 1 or 2 */ +#define SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING -6 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING -7 + +/* DTX setting not valid, use 0 or 1 */ +#define SKP_SILK_ENC_INVALID_DTX_SETTING -8 + +/* Internal encoder error */ +#define SKP_SILK_ENC_INTERNAL_ERROR -9 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SKP_SILK_DEC_INVALID_SAMPLING_FREQUENCY -10 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SKP_SILK_DEC_PAYLOAD_TOO_LARGE -11 + +/* Payload has bit errors */ +#define SKP_SILK_DEC_PAYLOAD_ERROR -12 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c b/pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c new file mode 100644 index 0000000..5a0c7c7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c @@ -0,0 +1,148 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void SKP_Silk_find_LPC_FIX( + SKP_int NLSF_Q15[], /* O NLSFs */ + SKP_int *interpIndex, /* O NLSF interpolation index, only used for NLSF interpolation */ + const SKP_int prev_NLSFq_Q15[], /* I previous NLSFs, only used for NLSF interpolation */ + const SKP_int useInterpolatedNLSFs, /* I Flag */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int16 x[], /* I Input signal */ + const SKP_int subfr_length /* I Input signal subframe length including preceeding samples */ +) +{ + SKP_int k; + SKP_int32 a_Q16[ MAX_LPC_ORDER ]; + SKP_int isInterpLower, shift; + SKP_int16 S[ MAX_LPC_ORDER ]; + SKP_int32 res_nrg0, res_nrg1; + SKP_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + SKP_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + SKP_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + SKP_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + SKP_int NLSF0_Q15[ MAX_LPC_ORDER ]; + SKP_int16 LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + /* Default: no interpolation */ + *interpIndex = 4; + + /* Burg AR analysis for the full frame */ + SKP_Silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, subfr_length, NB_SUBFR, SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); + + SKP_Silk_bwexpander_32( a_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); + + if( useInterpolatedNLSFs == 1 ) { + + /* Optimal solution for last 10 ms */ + SKP_Silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + ( NB_SUBFR >> 1 ) * subfr_length, + subfr_length, ( NB_SUBFR >> 1 ), SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); + + SKP_Silk_bwexpander_32( a_tmp_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); + + /* 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 - SKP_RSHIFT( res_tmp_nrg, shift ); + } + } else { + SKP_assert( shift > -32 ); + res_nrg = SKP_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + SKP_Silk_A2NLSF( NLSF_Q15, a_tmp_Q16, LPC_order ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + SKP_Silk_interpolate( NLSF0_Q15, prev_NLSFq_Q15, NLSF_Q15, k, LPC_order ); + + /* Convert to LPC for residual energy evaluation */ + SKP_Silk_NLSF2A_stable( a_tmp_Q12, NLSF0_Q15, LPC_order ); + + /* Calculate residual energy with NLSF interpolation */ + SKP_memset( S, 0, LPC_order * sizeof( SKP_int16 ) ); + SKP_Silk_LPC_analysis_filter( x, a_tmp_Q12, S, LPC_res, 2 * subfr_length, LPC_order ); + + SKP_Silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + LPC_order, subfr_length - LPC_order ); + SKP_Silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + LPC_order + subfr_length, subfr_length - LPC_order ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = SKP_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = SKP_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = SKP_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( SKP_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = SKP_TRUE; + } else { + isInterpLower = SKP_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < SKP_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = SKP_TRUE; + } else { + isInterpLower = SKP_FALSE; + } + } else { + isInterpLower = SKP_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == SKP_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + *interpIndex = k; + } + } + } + + if( *interpIndex == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + SKP_Silk_A2NLSF( NLSF_Q15, a_Q16, LPC_order ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c b/pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c new file mode 100644 index 0000000..4d047ff --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c @@ -0,0 +1,243 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Head room for correlations */ +#define LTP_CORRS_HEAD_ROOM 2 + +void SKP_Silk_fit_LTP( + SKP_int32 LTP_coefs_Q16[ LTP_ORDER ], + SKP_int16 LTP_coefs_Q14[ LTP_ORDER ] +); + +void SKP_Silk_find_LTP_FIX( + SKP_int16 b_Q14[ NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + SKP_int32 WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + SKP_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const SKP_int16 r_first[], /* I residual signal after LPC signal + state for first 10 ms */ + const SKP_int16 r_last[], /* I residual signal after LPC signal + state for last 10 ms */ + const SKP_int lag[ NB_SUBFR ], /* I LTP lags */ + const SKP_int32 Wght_Q15[ NB_SUBFR ], /* I weights */ + const SKP_int subfr_length, /* I subframe length */ + const SKP_int mem_offset, /* I number of samples in LTP memory */ + SKP_int corr_rshifts[ NB_SUBFR ] /* O right shifts applied to correlations */ +) +{ + SKP_int i, k, lshift; + const SKP_int16 *r_ptr, *lag_ptr; + SKP_int16 *b_Q14_ptr; + + SKP_int32 regu; + SKP_int32 *WLTP_ptr; + SKP_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ NB_SUBFR ], nrg[ NB_SUBFR ], g_Q26; + SKP_int32 w[ NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits; + + SKP_int32 temp32, denom32; + SKP_int extra_shifts; + SKP_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs; + SKP_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16; + SKP_int32 Rr[ LTP_ORDER ], rr[ NB_SUBFR ]; + SKP_int32 wd, m_Q12; + + b_Q14_ptr = b_Q14; + WLTP_ptr = WLTP; + r_ptr = &r_first[ mem_offset ]; + for( k = 0; k < NB_SUBFR; k++ ) { + if( k == ( NB_SUBFR >> 1 ) ) { /* shift residual for last 10 ms */ + r_ptr = &r_last[ mem_offset ]; + } + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + SKP_Silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */ + + /* Assure headroom */ + LZs = SKP_Silk_CLZ32( rr[k] ); + if( LZs < LTP_CORRS_HEAD_ROOM ) { + rr[ k ] = SKP_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs ); + rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs ); + } + corr_rshifts[ k ] = rr_shifts; + SKP_Silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ] ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */ + + /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */ + SKP_Silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ] ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */ + if( corr_rshifts[ k ] > rr_shifts ) { + rr[ k ] = SKP_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */ + } + SKP_assert( rr[ k ] >= 0 ); + + regu = 1; + regu = SKP_SMLAWB( regu, rr[ k ], SKP_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = SKP_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SKP_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = SKP_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SKP_FIX_CONST( LTP_DAMPING/3, 16 ) ); + SKP_Silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER ); + + SKP_Silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */ + + /* Limit and store in Q14 */ + SKP_Silk_fit_LTP( b_Q16, b_Q14_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = SKP_Silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */ + + /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */ + extra_shifts = SKP_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM ); + denom32 = SKP_LSHIFT_SAT32( SKP_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + SKP_RSHIFT( SKP_SMULWB( subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + denom32 = SKP_max( denom32, 1 ); + SKP_assert( ((SKP_int64)Wght_Q15[ k ] << 16 ) < SKP_int32_MAX ); /* Wght always < 0.5 in Q0 */ + temp32 = SKP_DIV32( SKP_LSHIFT( ( SKP_int32 )Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */ + temp32 = SKP_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */ + + /* Limit temp such that the below scaling never wraps around */ + WLTP_max = 0; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + WLTP_max = SKP_max( WLTP_ptr[ i ], WLTP_max ); + } + lshift = SKP_Silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */ + SKP_assert( 26 - 18 + lshift >= 0 ); + if( 26 - 18 + lshift < 31 ) { + temp32 = SKP_min_32( temp32, SKP_LSHIFT( ( SKP_int32 )1, 26 - 18 + lshift ) ); + } + + SKP_Silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */ + + w[ k ] = matrix_ptr( WLTP_ptr, ( LTP_ORDER >> 1 ), ( LTP_ORDER >> 1 ), LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */ + SKP_assert( w[k] >= 0 ); + + r_ptr += subfr_length; + b_Q14_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + maxRshifts = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + maxRshifts = SKP_max_int( corr_rshifts[ k ], maxRshifts ); + } + + /* Compute LTP coding gain */ + if( LTPredCodGain_Q7 != NULL ) { + LPC_LTP_res_nrg = 0; + LPC_res_nrg = 0; + SKP_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */ + for( k = 0; k < NB_SUBFR; k++ ) { + LPC_res_nrg = SKP_ADD32( LPC_res_nrg, SKP_RSHIFT( SKP_ADD32( SKP_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + LPC_LTP_res_nrg = SKP_ADD32( LPC_LTP_res_nrg, SKP_RSHIFT( SKP_ADD32( SKP_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + } + LPC_LTP_res_nrg = SKP_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */ + + div_Q16 = SKP_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 ); + *LTPredCodGain_Q7 = ( SKP_int )SKP_SMULBB( 3, SKP_Silk_lin2log( div_Q16 ) - ( 16 << 7 ) ); + + SKP_assert( *LTPredCodGain_Q7 == ( SKP_int )SKP_SAT16( SKP_MUL( 3, SKP_Silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) ); + } + + /* smoothing */ + /* d = sum( B, 1 ); */ + b_Q14_ptr = b_Q14; + for( k = 0; k < NB_SUBFR; k++ ) { + d_Q14[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d_Q14[ k ] += b_Q14_ptr[ i ]; + } + b_Q14_ptr += LTP_ORDER; + } + + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + + /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */ + max_abs_d_Q14 = 0; + max_w_bits = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + max_abs_d_Q14 = SKP_max_32( max_abs_d_Q14, SKP_abs( d_Q14[ k ] ) ); + /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */ + /* Find bits needed in Q( 18 - maxRshifts ) */ + max_w_bits = SKP_max_32( max_w_bits, 32 - SKP_Silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts ); + } + + /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -SKP_int16_MIN */ + SKP_assert( max_abs_d_Q14 <= ( 5 << 15 ) ); + + /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */ + extra_shifts = max_w_bits + 32 - SKP_Silk_CLZ32( max_abs_d_Q14 ) - 14; + + /* Subtract what we got available; bits in output var plus maxRshifts */ + extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */ + extra_shifts = SKP_max_int( extra_shifts, 0 ); + + maxRshifts_wxtra = maxRshifts + extra_shifts; + + temp32 = SKP_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */ + wd = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + /* w has at least 2 bits of headroom so no overflow should happen */ + temp32 = SKP_ADD32( temp32, SKP_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */ + wd = SKP_ADD32( wd, SKP_LSHIFT( SKP_SMULWW( SKP_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */ + } + m_Q12 = SKP_DIV32_varQ( wd, temp32, 12 ); + + b_Q14_ptr = b_Q14; + for( k = 0; k < NB_SUBFR; k++ ) { + /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */ + if( 2 - corr_rshifts[k] > 0 ) { + temp32 = SKP_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] ); + } else { + temp32 = SKP_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 ); + } + + g_Q26 = SKP_MUL( + SKP_DIV32( + SKP_FIX_CONST( LTP_SMOOTHING, 26 ), + SKP_RSHIFT( SKP_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */ + SKP_LSHIFT_SAT32( SKP_SUB_SAT32( ( SKP_int32 )m_Q12, SKP_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */ + + temp32 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b_Q14[ i ] = SKP_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */ + temp32 += delta_b_Q14[ i ]; /* Q14 */ + } + temp32 = SKP_DIV32( g_Q26, temp32 ); /* Q14->Q12 */ + for( i = 0; i < LTP_ORDER; i++ ) { + b_Q14_ptr[ i ] = SKP_LIMIT_32( ( SKP_int32 )b_Q14_ptr[ i ] + SKP_SMULWB( SKP_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 ); + } + b_Q14_ptr += LTP_ORDER; + } +} + +void SKP_Silk_fit_LTP( + SKP_int32 LTP_coefs_Q16[ LTP_ORDER ], + SKP_int16 LTP_coefs_Q14[ LTP_ORDER ] +) +{ + SKP_int i; + + for( i = 0; i < LTP_ORDER; i++ ) { + LTP_coefs_Q14[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c b/pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c new file mode 100644 index 0000000..a8fe42e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c @@ -0,0 +1,125 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Find pitch lags */ +void SKP_Silk_find_pitch_lags_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + SKP_int16 res[], /* O residual */ + const SKP_int16 x[] /* I Speech signal */ +) +{ + SKP_Silk_predict_state_FIX *psPredSt = &psEnc->sPred; + SKP_int buf_len, i, scale; + SKP_int32 thrhld_Q15, res_nrg; + const SKP_int16 *x_buf, *x_buf_ptr; + SKP_int16 Wsig[ FIND_PITCH_LPC_WIN_MAX ], *Wsig_ptr; + SKP_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + SKP_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_int32 FiltState[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + + /******************************************/ + /* Setup buffer lengths etc based on Fs */ + /******************************************/ + buf_len = SKP_ADD_LSHIFT( psEnc->sCmn.la_pitch, psEnc->sCmn.frame_length, 1 ); + + /* Safty check */ + SKP_assert( buf_len >= psPredSt->pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.frame_length; + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psPredSt->pitch_LPC_win_length; + Wsig_ptr = Wsig; + SKP_Silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + SKP_memcpy( Wsig_ptr, x_buf_ptr, ( psPredSt->pitch_LPC_win_length - SKP_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( SKP_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psPredSt->pitch_LPC_win_length - SKP_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_buf_ptr += psPredSt->pitch_LPC_win_length - SKP_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + SKP_Silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + SKP_Silk_autocorr( auto_corr, &scale, Wsig, psPredSt->pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = SKP_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SKP_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + + /* Calculate the reflection coefficients using schur */ + res_nrg = SKP_Silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = SKP_DIV32_varQ( auto_corr[ 0 ], SKP_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + SKP_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 ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + SKP_Silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SKP_FIX_CONST( FIND_PITCH_BANDWITH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + SKP_memset( FiltState, 0, psEnc->sCmn.pitchEstimationLPCOrder * sizeof( SKP_int32 ) ); /* Not really necessary, but Valgrind will complain otherwise */ + SKP_Silk_MA_Prediction( x_buf, A_Q12, FiltState, res, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + SKP_memset( res, 0, psEnc->sCmn.pitchEstimationLPCOrder * sizeof( SKP_int16 ) ); + + /* Threshold for pitch estimator */ + thrhld_Q15 = SKP_FIX_CONST( 0.45, 15 ); + thrhld_Q15 = SKP_SMLABB( thrhld_Q15, SKP_FIX_CONST( -0.004, 15 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q15 = SKP_SMLABB( thrhld_Q15, SKP_FIX_CONST( -0.1, 7 ), psEnc->speech_activity_Q8 ); + thrhld_Q15 = SKP_SMLABB( thrhld_Q15, SKP_FIX_CONST( 0.15, 15 ), psEnc->sCmn.prev_sigtype ); + thrhld_Q15 = SKP_SMLAWB( thrhld_Q15, SKP_FIX_CONST( -0.1, 16 ), psEncCtrl->input_tilt_Q15 ); + thrhld_Q15 = SKP_SAT16( thrhld_Q15 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + psEncCtrl->sCmn.sigtype = SKP_Silk_pitch_analysis_core( res, psEncCtrl->sCmn.pitchL, &psEncCtrl->sCmn.lagIndex, + &psEncCtrl->sCmn.contourIndex, &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + ( SKP_int16 )thrhld_Q15, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, SKP_FALSE ); +} diff --git a/pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c b/pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c new file mode 100644 index 0000000..11764a6 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + + +void SKP_Silk_find_pred_coefs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const SKP_int16 res_pitch[] /* I Residual from pitch analysis */ +) +{ + SKP_int i; + SKP_int32 WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + SKP_int32 invGains_Q16[ NB_SUBFR ], local_gains[ NB_SUBFR ], Wght_Q15[ NB_SUBFR ]; + SKP_int NLSF_Q15[ MAX_LPC_ORDER ]; + const SKP_int16 *x_ptr; + SKP_int16 *x_pre_ptr, LPC_in_pre[ NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + SKP_int32 tmp, min_gain_Q16; + SKP_int LTP_corrs_rshift[ NB_SUBFR ]; + + + /* weighting for weighted least squares */ + min_gain_Q16 = SKP_int32_MAX >> 6; + for( i = 0; i < NB_SUBFR; i++ ) { + min_gain_Q16 = SKP_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < NB_SUBFR; i++ ) { + /* Divide to Q16 */ + SKP_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 ] = SKP_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Ensure Wght_Q15 a minimum value 1 */ + invGains_Q16[ i ] = SKP_max( invGains_Q16[ i ], 363 ); + + /* Square the inverted gains */ + SKP_assert( invGains_Q16[ i ] == SKP_SAT16( invGains_Q16[ i ] ) ); + tmp = SKP_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] ); + Wght_Q15[ i ] = SKP_RSHIFT( tmp, 1 ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = SKP_DIV32( ( 1 << 16 ), invGains_Q16[ i ] ); + } + + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + SKP_assert( psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->sCmn.pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + SKP_Silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7, res_pitch, + res_pitch + SKP_RSHIFT( psEnc->sCmn.frame_length, 1 ), psEncCtrl->sCmn.pitchL, Wght_Q15, + psEnc->sCmn.subfr_length, psEnc->sCmn.frame_length, LTP_corrs_rshift ); + + + /* Quantize LTP gain parameters */ + SKP_Silk_quant_LTP_gains_FIX( psEncCtrl->LTPCoef_Q14, psEncCtrl->sCmn.LTPIndex, &psEncCtrl->sCmn.PERIndex, + WLTP, psEnc->mu_LTP_Q8, psEnc->sCmn.LTPQuantLowComplexity ); + + /* Control LTP scaling */ + SKP_Silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl ); + + /* Create LTP residual */ + SKP_Silk_LTP_analysis_filter_FIX( LPC_in_pre, psEnc->x_buf + psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder, + psEncCtrl->LTPCoef_Q14, psEncCtrl->sCmn.pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = psEnc->x_buf + psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < NB_SUBFR; i++ ) { + SKP_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; + } + + SKP_memset( psEncCtrl->LTPCoef_Q14, 0, NB_SUBFR * LTP_ORDER * sizeof( SKP_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + TIC(FIND_LPC) + SKP_Silk_find_LPC_FIX( NLSF_Q15, &psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sPred.prev_NLSFq_Q15, + psEnc->sCmn.useInterpolatedNLSFs * ( 1 - psEnc->sCmn.first_frame_after_reset ), psEnc->sCmn.predictLPCOrder, + LPC_in_pre, psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + TOC(FIND_LPC) + + + /* Quantize LSFs */ + TIC(PROCESS_LSFS) + SKP_Silk_process_NLSFs_FIX( psEnc, psEncCtrl, NLSF_Q15 ); + TOC(PROCESS_LSFS) + + /* Calculate residual energy using quantized LPC coefficients */ + SKP_Silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for fluctuation reduction */ + SKP_memcpy( psEnc->sPred.prev_NLSFq_Q15, NLSF_Q15, psEnc->sCmn.predictLPCOrder * sizeof( SKP_int ) ); + +} + diff --git a/pkg/silk/csilk/SKP_Silk_gain_quant.c b/pkg/silk/csilk/SKP_Silk_gain_quant.c new file mode 100644 index 0000000..c33fe49 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_gain_quant.c @@ -0,0 +1,94 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 ) +#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) +#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) ) + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void SKP_Silk_gains_quant( + SKP_int ind[ NB_SUBFR ], /* O gain indices */ + SKP_int32 gain_Q16[ NB_SUBFR ], /* I/O gains (quantized out) */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +) +{ + SKP_int k; + + for( k = 0; k < NB_SUBFR; k++ ) { + /* Add half of previous quantization error, convert to log scale, scale, floor() */ + ind[ k ] = SKP_SMULWB( SCALE_Q16, SKP_Silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = SKP_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + ind[ k ] = SKP_max_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = SKP_LIMIT_int( ind[ k ] - *prev_ind, MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + /* Accumulate deltas */ + *prev_ind += ind[ k ]; + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Convert to linear scale and scale */ + gain_Q16[ k ] = SKP_Silk_log2lin( SKP_min_32( SKP_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3968 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void SKP_Silk_gains_dequant( + SKP_int32 gain_Q16[ NB_SUBFR ], /* O quantized gains */ + const SKP_int ind[ NB_SUBFR ], /* I gain indices */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +) +{ + SKP_int k; + + for( k = 0; k < NB_SUBFR; k++ ) { + if( k == 0 && conditional == 0 ) { + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + *prev_ind += ind[ k ] + MIN_DELTA_GAIN_QUANT; + } + + /* Convert to linear scale and scale */ + gain_Q16[ k ] = SKP_Silk_log2lin( SKP_min_32( SKP_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3968 = 31 in Q7 */ + } +} diff --git a/pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c b/pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c new file mode 100644 index 0000000..7fa445c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +SKP_int SKP_Silk_init_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +) { + SKP_int ret = 0; + /* Clear the entire encoder state */ + SKP_memset( psEnc, 0, sizeof( SKP_Silk_encoder_state_FIX ) ); + +#if HIGH_PASS_INPUT + psEnc->variable_HP_smth1_Q15 = 200844; /* = SKP_Silk_log2(70)_Q0; */ + psEnc->variable_HP_smth2_Q15 = 200844; /* = SKP_Silk_log2(70)_Q0; */ +#endif + + /* Used to deactivate e.g. LSF interpolation and fluctuation reduction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += SKP_Silk_VAD_Init( &psEnc->sCmn.sVAD ); + + /* Initialize NSQ */ + psEnc->sCmn.sNSQ.prev_inv_gain_Q16 = 65536; + psEnc->sCmn.sNSQ_LBRR.prev_inv_gain_Q16 = 65536; + + return( ret ); +} diff --git a/pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c b/pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c new file mode 100644 index 0000000..8e738f2 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_inner_prod_aligned.c * + * * + * * + * Copyright 2008-2010 (c), Skype Limited * + * Date: 080601 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* sum= for(i=0;i6, memory access can be reduced by half. */ + +#if (EMBEDDED_ARM<5) +SKP_int32 SKP_Silk_inner_prod_aligned( + const SKP_int16* const inVec1, /* I input vector 1 */ + const SKP_int16* const inVec2, /* I input vector 2 */ + const SKP_int len /* I vector lengths */ +) +{ + SKP_int i; + SKP_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = SKP_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} +#endif + +#if (EMBEDDED_ARM<5) +SKP_int64 SKP_Silk_inner_prod16_aligned_64( + const SKP_int16 *inVec1, /* I input vector 1 */ + const SKP_int16 *inVec2, /* I input vector 2 */ + const SKP_int len /* I vector lengths */ +) +{ + SKP_int i; + SKP_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = SKP_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_interpolate.c b/pkg/silk/csilk/SKP_Silk_interpolate.c new file mode 100644 index 0000000..73b9eb5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_interpolate.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Interpolate two vectors */ +void SKP_Silk_interpolate( + SKP_int xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const SKP_int x0[ MAX_LPC_ORDER ], /* I first vector */ + const SKP_int x1[ MAX_LPC_ORDER ], /* I second vector */ + const SKP_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const SKP_int d /* I number of parameters */ +) +{ + SKP_int i; + + SKP_assert( ifact_Q2 >= 0 ); + SKP_assert( ifact_Q2 <= ( 1 << 2 ) ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = ( SKP_int )( ( SKP_int32 )x0[ i ] + SKP_RSHIFT( SKP_MUL( ( SKP_int32 )x1[ i ] - ( SKP_int32 )x0[ i ], ifact_Q2 ), 2 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_k2a.c b/pkg/silk/csilk/SKP_Silk_k2a.c new file mode 100644 index 0000000..3d3d19a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_k2a.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_k2a.c * + * * + * Step up function, converts reflection coefficients to prediction * + * coefficients * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a( + SKP_int32 *A_Q24, /* O: Prediction coefficients [order] Q24 */ + const SKP_int16 *rc_Q15, /* I: Reflection coefficients [order] Q15 */ + const SKP_int32 order /* I: Prediction order */ +) +{ + SKP_int k, n; + SKP_int32 Atmp[ SKP_Silk_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = SKP_SMLAWB( A_Q24[ n ], SKP_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] ); + } + A_Q24[ k ] = -SKP_LSHIFT( (SKP_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_k2a_Q16.c b/pkg/silk/csilk/SKP_Silk_k2a_Q16.c new file mode 100644 index 0000000..176f24e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_k2a_Q16.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_k2a.c * + * * + * Step up function, converts reflection coefficients to prediction * + * coefficients * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void SKP_Silk_k2a_Q16( + SKP_int32 *A_Q24, /* O: Prediction coefficients [order] Q24 */ + const SKP_int32 *rc_Q16, /* I: Reflection coefficients [order] Q16 */ + const SKP_int32 order /* I: Prediction order */ +) +{ + SKP_int k, n; + SKP_int32 Atmp[ SKP_Silk_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = SKP_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] ); + } + A_Q24[ k ] = -SKP_LSHIFT( rc_Q16[ k ], 8 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_lin2log.c b/pkg/silk/csilk/SKP_Silk_lin2log.c new file mode 100644 index 0000000..b917c97 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_lin2log.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_lin2log.c * + * * + * Convert input to a log scale * + * Approximation of 128 * log2() * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" +#if EMBEDDED_ARM<4 +/* Approximation of 128 * log2() (very close inverse of approx 2^() below) */ +/* Convert input to a log scale */ +SKP_int32 SKP_Silk_lin2log( const SKP_int32 inLin ) /* I: Input in linear scale */ +{ + SKP_int32 lz, frac_Q7; + + SKP_Silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return( SKP_LSHIFT( 31 - lz, 7 ) + SKP_SMLAWB( frac_Q7, SKP_MUL( frac_Q7, 128 - frac_Q7 ), 179 ) ); +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_log2lin.c b/pkg/silk/csilk/SKP_Silk_log2lin.c new file mode 100644 index 0000000..0124c30 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_log2lin.c @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_log2lin.c * + * * + * Convert input to a linear scale * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of SKP_Silk_lin2log()) */ +/* Convert input to a linear scale */ +SKP_int32 SKP_Silk_log2lin( const SKP_int32 inLog_Q7 ) /* I: Input on log scale */ +{ + SKP_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return( 0 ); + } else if( inLog_Q7 >= ( 31 << 7 ) ) { + /* Saturate, and prevent wrap-around */ + return( SKP_int32_MAX ); + } + + out = SKP_LSHIFT( 1, SKP_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = SKP_ADD_RSHIFT( out, SKP_MUL( out, SKP_SMLAWB( frac_Q7, SKP_MUL( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = SKP_MLA( out, SKP_RSHIFT( out, 7 ), SKP_SMLAWB( frac_Q7, SKP_MUL( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/pkg/silk/csilk/SKP_Silk_macros.h b/pkg/silk/csilk/SKP_Silk_macros.h new file mode 100644 index 0000000..9ccd750 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_macros.h @@ -0,0 +1,125 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _SKP_SILK_API_C_H_ +#define _SKP_SILK_API_C_H_ + +// This is an inline header file for general platform. + +// (a32 * (SKP_int32)((SKP_int16)(b32))) >> 16 output have to be 32bit int +#define SKP_SMULWB(a32, b32) ((((a32) >> 16) * (SKP_int32)((SKP_int16)(b32))) + ((((a32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(b32))) >> 16)) + +// a32 + (b32 * (SKP_int32)((SKP_int16)(c32))) >> 16 output have to be 32bit int +#define SKP_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (SKP_int32)((SKP_int16)(c32))) + ((((b32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(c32))) >> 16))) + +// (a32 * (b32 >> 16)) >> 16 +#define SKP_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) + +// a32 + (b32 * (c32 >> 16)) >> 16 +#define SKP_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) + +// (SKP_int32)((SKP_int16)(a3))) * (SKP_int32)((SKP_int16)(b32)) output have to be 32bit int +#define SKP_SMULBB(a32, b32) ((SKP_int32)((SKP_int16)(a32)) * (SKP_int32)((SKP_int16)(b32))) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (SKP_int32)((SKP_int16)(c32)) output have to be 32bit int +#define SKP_SMLABB(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * (SKP_int32)((SKP_int16)(c32))) + +// (SKP_int32)((SKP_int16)(a32)) * (b32 >> 16) +#define SKP_SMULBT(a32, b32) ((SKP_int32)((SKP_int16)(a32)) * ((b32) >> 16)) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (c32 >> 16) +#define SKP_SMLABT(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * ((c32) >> 16)) + +// a64 + (b32 * c32) +#define SKP_SMLAL(a64, b32, c32) (SKP_ADD64((a64), ((SKP_int64)(b32) * (SKP_int64)(c32)))) + +// (a32 * b32) >> 16 +#define SKP_SMULWW(a32, b32) SKP_MLA(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)) + +// a32 + ((b32 * c32) >> 16) +#define SKP_SMLAWW(a32, b32, c32) SKP_MLA(SKP_SMLAWB((a32), (b32), (c32)), (b32), SKP_RSHIFT_ROUND((c32), 16)) + +// (SKP_int32)(((SKP_int64)a32 * b32) >> 32) +#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) + +/* add/subtract with output saturated */ +#define SKP_ADD_SAT32(a, b) ((((a) + (b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? SKP_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? SKP_int32_MAX : (a)+(b)) ) + +#define SKP_SUB_SAT32(a, b) ((((a)-(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? SKP_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? SKP_int32_MAX : (a)-(b)) ) + +SKP_INLINE SKP_int32 SKP_Silk_CLZ16(SKP_int16 in16) +{ + SKP_int32 out32 = 0; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +SKP_INLINE SKP_int32 SKP_Silk_CLZ32(SKP_int32 in32) +{ + /* test highest 16 bits and convert to SKP_int16 */ + if( in32 & 0xFFFF0000 ) { + return SKP_Silk_CLZ16((SKP_int16)(in32 >> 16)); + } else { + return SKP_Silk_CLZ16((SKP_int16)in32) + 16; + } +} + +#endif //_SKP_SILK_API_C_H_ + diff --git a/pkg/silk/csilk/SKP_Silk_macros_arm.h b/pkg/silk/csilk/SKP_Silk_macros_arm.h new file mode 100644 index 0000000..4e9d3c2 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_macros_arm.h @@ -0,0 +1,248 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _SKP_SILK_API_ARM_H_ +#define _SKP_SILK_API_ARM_H_ + +// This is an inline header file for embedded arm platform. + +#if EMBEDDED_ARM==4 +extern SKP_int32 SKP_Silk_CLZ16(SKP_int16 in16); +extern SKP_int32 SKP_Silk_CLZ32(SKP_int32 in32); + +// (a32 * (SKP_int32)((SKP_int16)(b32))) >> 16 +#define SKP_SMULWB(a32, b32) ((((a32) >> 16) * (SKP_int32)((SKP_int16)(b32))) + ((((a32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(b32))) >> 16)) + +// a32 + (b32 * (SKP_int32)((SKP_int16)(c32))) >> 16 +#define SKP_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (SKP_int32)((SKP_int16)(c32))) + ((((b32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(c32))) >> 16))) + +/*SKP_INLINE SKP_int32 SKP_SMULWT(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int32 out32, tmp; + SKP_int32 tmp32=0xFFFF0000; + asm volatile("and %1, %3, %4 \n\t smull %3, %0, %2, %1" : "=&r" (out32), "=&r" (tmp) : "r" (a32), "r" (b32), "r" (tmp32)); + return(out32); +}*/ + +// (a32 * (b32 >> 16)) >> 16 +#define SKP_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) + +// a32 + (b32 * (c32 >> 16)) >> 16 +#define SKP_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) + +// (SKP_int32)((SKP_int16)(a3))) * (SKP_int32)((SKP_int16)(b32)) +#define SKP_SMULBB(a32, b32) ((SKP_int32)((SKP_int16)(a32)) * (SKP_int32)((SKP_int16)(b32))) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (SKP_int32)((SKP_int16)(c32)) +#define SKP_SMLABB(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * (SKP_int32)((SKP_int16)(c32))) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (SKP_int32)((SKP_int16)(c32)) +#define SKP_SMLABB_ovflw(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * (SKP_int32)((SKP_int16)(c32))) + +// (SKP_int32)((SKP_int16)(a32)) * (b32 >> 16) +#define SKP_SMULBT(a32, b32) ((SKP_int32)((SKP_int16)(a32)) * ((b32) >> 16)) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (c32 >> 16) +#define SKP_SMLABT(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * ((c32) >> 16)) + +SKP_INLINE SKP_int64 SKP_SMLAL(SKP_int64 a64, SKP_int32 b32, SKP_int32 c32) +{ +#ifdef IPHONE + // IPHONE LLVM compiler doesn't understand Q/R representation. + a64 = (SKP_int64)b32 * c32; + return(a64); +#else + __asm__ __volatile__ ("smlal %Q0, %R0, %2, %3" : "=r" (a64) : "0" (a64), "r" (b32), "r" (c32)); + return(a64); +#endif +} + +// (a32 * b32) >> 16 +#define SKP_SMULWW(a32, b32) SKP_MLA(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)) + +// a32 + ((b32 * c32) >> 16) +#define SKP_SMLAWW(a32, b32, c32) SKP_MLA(SKP_SMLAWB((a32), (b32), (c32)), (b32), SKP_RSHIFT_ROUND((c32), 16)) + +/* add/subtract with output saturated */ +#define SKP_ADD_SAT32(a, b) ((((a) + (b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? SKP_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? SKP_int32_MAX : (a)+(b)) ) + +#define SKP_SUB_SAT32(a, b) ((((a)-(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? SKP_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? SKP_int32_MAX : (a)-(b)) ) + +#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) + + +#else +SKP_INLINE SKP_int32 SKP_SMULWB(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("smulwb %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + + +SKP_INLINE SKP_int32 SKP_SMLAWB(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlawb %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMULWT(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smulwt %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLAWT(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smlawt %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMULBB(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("smulbb %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLABB(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlabb %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLABB_ovflw(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlabb %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMULBT(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("smulbt %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLABT(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlabt %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int64 SKP_SMLAL(SKP_int64 a64, SKP_int32 b32, SKP_int32 c32) +{ +#ifdef IPHONE + // IPHONE LLVM compiler doesn't understand Q/R representation. + a64 = (SKP_int64)b32 * c32; + return(a64); +#else + __asm__ __volatile__ ("smlal %Q0, %R0, %2, %3" : "=r" (a64) : "0" (a64), "r" (b32), "r" (c32)); + return(a64); +#endif +} + +#define SKP_SMULWW(a32, b32) SKP_MLA(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)) + +/*SKP_INLINE SKP_int32 SKP_SMULWW(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int64 tmp; + SKP_int32 out32; + __asm__ __volatile__ ("smull %Q1, %R1, %2, %3 \n\t mov %0, %R1, lsl #16 \n\t add %0, %0, %Q1, lsr #16" : "=&r" (out32), "=&r" (tmp) : "r" (a32), "r" (b32)); + return(out32); +}*/ +#define SKP_SMLAWW(a32, b32, c32) SKP_MLA(SKP_SMLAWB((a32), (b32), (c32)), (b32), SKP_RSHIFT_ROUND((c32), 16)) +/*SKP_INLINE SKP_int32 SKP_SMLAWW(a32, b32, c32){ + SKP_int64 tmp; + SKP_int32 out32; + __asm__ __volatile__ ("smull %Q1, %R1, %3, %4 \n\t add %0, %2, %R1, lsl #16 \n\t add %0, %0, %Q1, lsr #16" : "=&r" (out32), "=&r" (tmp) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +}*/ + +SKP_INLINE SKP_int32 SKP_ADD_SAT32(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("qadd %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SUB_SAT32(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("qsub %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_Silk_CLZ16(SKP_int16 in16) +{ + SKP_int32 out32; + __asm__ __volatile__ ("movs %0, %1, lsl #16 \n\tclz %0, %0 \n\t it eq \n\t moveq %0, #16" : "=r" (out32) : "r" (in16) : "cc"); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_Silk_CLZ32(SKP_int32 in32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("clz %0, %1" : "=r" (out32) : "r" (in32)); + return(out32); +} +#if EMBEDDED_ARM < 6 +#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) +#endif +#endif + +// Some ARMv6 specific instructions: + +#if EMBEDDED_ARM>=6 + +SKP_INLINE SKP_int32 SKP_SMMUL(SKP_int32 a32, SKP_int32 b32){ + SKP_int32 out32; + __asm__ __volatile__ ("smmul %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMUAD(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smuad %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLAD(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smlad %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +#endif + +#endif // _SKP_SILK_API_ARM_H_ + + + diff --git a/pkg/silk/csilk/SKP_Silk_main.h b/pkg/silk/csilk/SKP_Silk_main.h new file mode 100644 index 0000000..bba7fa7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_main.h @@ -0,0 +1,388 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_MAIN_H +#define SKP_SILK_MAIN_H + +#include "SKP_Silk_SigProc_FIX.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "SKP_Silk_define.h" +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables.h" +#include "SKP_Silk_PLC.h" + + +/* Encodes signs of excitation */ +void SKP_Silk_encode_signs( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int8 q[], /* I pulse signal */ + const SKP_int length, /* I length of input */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate Level Index */ +); + +/* Decodes signs of excitation */ +void SKP_Silk_decode_signs( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + SKP_int q[], /* I/O pulse signal */ + const SKP_int length, /* I length of output */ + const SKP_int sigtype, /* I Signal type */ + const SKP_int QuantOffsetType, /* I Quantization offset type */ + const SKP_int RateLevelIndex /* I Rate Level Index */ +); + +/* Control internal sampling rate */ +SKP_int SKP_Silk_control_audio_bandwidth( + SKP_Silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + const SKP_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void SKP_Silk_encode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int sigtype, /* I Sigtype */ + const SKP_int QuantOffsetType, /* I QuantOffsetType */ + const SKP_int8 q[], /* I quantization indices */ + const SKP_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_encoder( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_decoder( + SKP_int *pulses0, /* O data: nonnegative pulse amplitudes */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/***************/ +/* Range coder */ +/***************/ +/* Range encoder for one symbol */ +void SKP_Silk_range_encoder( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data, /* I uncompressed data */ + const SKP_uint16 prob[] /* I cumulative density functions */ +); + +/* Range encoder for multiple symbols */ +void SKP_Silk_range_encoder_multi( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data[], /* I uncompressed data [nSymbols] */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int nSymbols /* I number of data symbols */ +); + +/* Range decoder for one symbol */ +void SKP_Silk_range_decoder( + SKP_int data[], /* O uncompressed data */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 prob[], /* I cumulative density function */ + SKP_int probIx /* I initial (middle) entry of cdf */ +); + +/* Range decoder for multiple symbols */ +void SKP_Silk_range_decoder_multi( + SKP_int data[], /* O uncompressed data [nSymbols] */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int probStartIx[], /* I initial (middle) entries of cdfs [nSymbols] */ + const SKP_int nSymbols /* I number of data symbols */ +); + +/* Initialize range coder structure for encoder */ +void SKP_Silk_range_enc_init( + SKP_Silk_range_coder_state *psRC /* O compressor data structure */ +); + +/* Initialize range coder structure for decoder */ +void SKP_Silk_range_dec_init( + SKP_Silk_range_coder_state *psRC, /* O compressor data structure */ + const SKP_uint8 buffer[], /* I buffer for compressed data [bufferLength] */ + const SKP_int32 bufferLength /* I buffer length (in bytes) */ +); + +/* Determine length of bitstream */ +SKP_int SKP_Silk_range_coder_get_length( /* O returns number of BITS in stream */ + const SKP_Silk_range_coder_state *psRC, /* I compressed data structure */ + SKP_int *nBytes /* O number of BYTES in stream */ +); + +/* Write decodable stream to buffer, and determine its length */ +void SKP_Silk_range_enc_wrap_up( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +); + +/* Check that any remaining bits in the last byte are set to 1 */ +void SKP_Silk_range_coder_check_after_decoding( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void SKP_Silk_gains_quant( + SKP_int ind[ NB_SUBFR ], /* O gain indices */ + SKP_int32 gain_Q16[ NB_SUBFR ], /* I/O gains (quantized out) */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void SKP_Silk_gains_dequant( + SKP_int32 gain_Q16[ NB_SUBFR ], /* O quantized gains */ + const SKP_int ind[ NB_SUBFR ], /* I gain indices */ + SKP_int *prev_ind, /* I/O last index in previous frame */ + const SKP_int conditional /* I first gain is delta coded if 1 */ +); + +/* Convert NLSF parameters to stable AR prediction filter coefficients */ +void SKP_Silk_NLSF2A_stable( + SKP_int16 pAR_Q12[ MAX_LPC_ORDER ], /* O Stabilized AR coefs [LPC_order] */ + const SKP_int pNLSF[ MAX_LPC_ORDER ], /* I NLSF vector [LPC_order] */ + const SKP_int LPC_order /* I LPC/LSF order */ +); + +/* Interpolate two vectors */ +void SKP_Silk_interpolate( + SKP_int xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const SKP_int x0[ MAX_LPC_ORDER ], /* I first vector */ + const SKP_int x1[ MAX_LPC_ORDER ], /* I second vector */ + const SKP_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const SKP_int d /* I number of parameters */ +); + +/***********************************/ +/* Noise shaping quantization (NSQ)*/ +/***********************************/ +void SKP_Silk_NSQ( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I prefiltered input signal */ + SKP_int8 q[], /* O quantized qulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefficients */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I Long term prediction coefficients */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/* Noise shaping using delayed decision */ +void SKP_Silk_NSQ_del_dec( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder State */ + SKP_Silk_encoder_control *psEncCtrlC, /* I Encoder Control */ + SKP_Silk_nsq_state *NSQ, /* I/O NSQ state */ + const SKP_int16 x[], /* I Prefiltered input signal */ + SKP_int8 q[], /* O Quantized pulse signal */ + const SKP_int LSFInterpFactor_Q2, /* I LSF interpolation factor in Q2 */ + const SKP_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Prediction coefs */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ], /* I LT prediction coefs */ + const SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I */ + const SKP_int HarmShapeGain_Q14[ NB_SUBFR ], /* I */ + const SKP_int Tilt_Q14[ NB_SUBFR ], /* I Spectral tilt */ + const SKP_int32 LF_shp_Q14[ NB_SUBFR ], /* I */ + const SKP_int32 Gains_Q16[ NB_SUBFR ], /* I */ + const SKP_int Lambda_Q10, /* I */ + const SKP_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +SKP_int SKP_Silk_VAD_Init( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Silk VAD noise level estimation */ +void SKP_Silk_VAD_GetNoiseLevels( + const SKP_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + SKP_Silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +SKP_int SKP_Silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + SKP_Silk_VAD_state *psSilk_VAD, /* I/O Silk VAD state */ + SKP_int *pSA_Q8, /* O Speech activity level in Q8 */ + SKP_int *pSNR_dB_Q7, /* O SNR for current frame in Q7 */ + SKP_int pQuality_Q15[ VAD_N_BANDS ], /* O Smoothed SNR for each band */ + SKP_int *pTilt_Q15, /* O current frame's frequency tilt */ + const SKP_int16 pIn[], /* I PCM input [framelength] */ + const SKP_int framelength /* I Input frame length */ +); + +/* Detect signal in 8 - 12 khz range */ +void SKP_Silk_detect_SWB_input( + SKP_Silk_detect_SWB_state *psSWBdetect, /* I/O Encoder state */ + const SKP_int16 samplesIn[], /* I Input to encoder */ + SKP_int nSamplesIn /* I Length of input */ +); + +#if SWITCH_TRANSITION_FILTERING +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void SKP_Silk_LP_variable_cutoff( + SKP_Silk_LP_state *psLP, /* I/O LP filter state */ + SKP_int16 *out, /* O Low-pass filtered output signal */ + const SKP_int16 *in, /* I Input signal */ + const SKP_int frame_length /* I Frame length */ +); +#endif + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +SKP_int SKP_Silk_create_decoder( + SKP_Silk_decoder_state **ppsDec /* I/O Decoder state pointer pointer */ +); + +SKP_int SKP_Silk_free_decoder( + SKP_Silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +SKP_int SKP_Silk_init_decoder( + SKP_Silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +void SKP_Silk_decoder_set_fs( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state pointer */ + SKP_int fs_kHz /* I Sampling frequency (kHz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +SKP_int SKP_Silk_decode_frame( + SKP_Silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + SKP_int16 pOut[], /* O Pointer to output speech frame */ + SKP_int16 *pN, /* O Pointer to size of output frame */ + const SKP_uint8 pCode[], /* I Pointer to payload */ + const SKP_int nBytes, /* I Payload length */ + SKP_int action, /* I Action from Jitter Buffer */ + SKP_int *decBytes /* O Used bytes to decode this frame */ +); + +/* Decode parameters from payload */ +void SKP_Silk_decode_parameters( + SKP_Silk_decoder_state *psDec, /* I/O State */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int fullDecoding /* I Flag to tell if only arithmetic decoding */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void SKP_Silk_decode_core( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I Decoder control */ + SKP_int16 xq[], /* O Decoded speech */ + const SKP_int q[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +); + +/* NLSF vector decoder */ +void SKP_Silk_NLSF_MSVQ_decode( + SKP_int *pNLSF_Q15, /* O Pointer to decoded output [LPC_ORDER x 1] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Pointer to NLSF codebook struct */ + const SKP_int *NLSFIndices, /* I Pointer to NLSF indices [nStages x 1] */ + const SKP_int LPC_order /* I LPC order */ +); + +/**********************/ +/* Arithmetic coding */ +/*********************/ + +/* Decode quantization indices of excitation (Shell coding) */ +void SKP_Silk_decode_pulses( + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int q[], /* O Excitation signal */ + const SKP_int frame_length /* I Frame length (preliminary) */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void SKP_Silk_CNG_Reset( + SKP_Silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void SKP_Silk_CNG( + SKP_Silk_decoder_state *psDec, /* I/O Decoder state */ + SKP_Silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + SKP_int16 signal[], /* I/O Signal */ + SKP_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void SKP_Silk_encode_parameters( + SKP_Silk_encoder_state *psEncC, /* I/O Encoder state */ + SKP_Silk_encoder_control *psEncCtrlC, /* I/O Encoder control */ + SKP_Silk_range_coder_state *psRC, /* I/O Range coder state */ + const SKP_int8 *q /* I Quantization indices */ +); + +/* Extract lowest layer encoding */ +void SKP_Silk_get_low_layer_internal( + const SKP_uint8 *indata, /* I: Encoded input vector */ + const SKP_int16 nBytesIn, /* I: Number of input Bytes */ + SKP_uint8 *Layer0data, /* O: Layer0 payload */ + SKP_int16 *nLayer0Bytes /* O: Number of FEC Bytes */ +); + +/* Resets LBRR buffer, used if packet size changes */ +void SKP_Silk_LBRR_reset( + SKP_Silk_encoder_state *psEncC /* I/O Pointer to Silk encoder state */ +); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_main_FIX.h b/pkg/silk/csilk/SKP_Silk_main_FIX.h new file mode 100644 index 0000000..4d760a4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_main_FIX.h @@ -0,0 +1,338 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_MAIN_FIX_H +#define SKP_SILK_MAIN_FIX_H + +#include +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_structs_FIX.h" +#include "SKP_Silk_main.h" +#include "SKP_Silk_PLC.h" +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* Initializes the Silk encoder state */ +SKP_int SKP_Silk_init_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +); + +/* Control the Silk encoder */ +SKP_int SKP_Silk_control_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state */ + const SKP_int PacketSize_ms, /* I Packet length (ms) */ + const SKP_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const SKP_int PacketLoss_perc, /* I Packet loss rate (in percent) */ + const SKP_int DTX_enabled, /* I Enable / disable DTX */ + const SKP_int Complexity /* I Complexity (0->low; 1->medium; 2->high) */ +); + +/* Encoder main function */ +SKP_int SKP_Silk_encode_frame_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes; */ + /* input: max length; output: used */ + const SKP_int16 *pIn /* I Pointer to input speech frame */ +); + +/* Low BitRate Redundancy encoding functionality. Reuse all parameters but encode with lower bitrate */ +void SKP_Silk_LBRR_encode_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes */ + SKP_int16 xfw[] /* I Input signal */ +); + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void SKP_Silk_HP_variable_cutoff_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + SKP_int16 *out, /* O high-pass filtered output signal */ + const SKP_int16 *in /* I input signal */ +); + +/****************/ +/* Prefiltering */ +/****************/ +void SKP_Silk_prefilter_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const SKP_Silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + SKP_int16 xw[], /* O Weighted signal */ + const SKP_int16 x[] /* I Speech signal */ +); + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +void SKP_Silk_noise_shape_analysis_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const SKP_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const SKP_int16 *x /* I Input signal [ frame_length + la_shape ] */ +); + +/* Autocorrelations for a warped frequency axis */ +void SKP_Silk_warped_autocorrelation_FIX( + SKP_int32 *corr, /* O Result [order + 1] */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *input, /* I Input data to correlate */ + const SKP_int16 warping_Q16, /* I Warping coefficient */ + const SKP_int length, /* I Length of input */ + const SKP_int order /* I Correlation order (even) */ +); + +/* Processing of gains */ +void SKP_Silk_process_gains_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O Encoder control */ +); + +/* Control low bitrate redundancy usage */ +void SKP_Silk_LBRR_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control *psEncCtrlC /* I/O encoder control */ +); + +/* Calculation of LTP state scaling */ +void SKP_Silk_LTP_scale_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O encoder control */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ + +/* Find pitch lags */ +void SKP_Silk_find_pitch_lags_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + SKP_int16 res[], /* O residual */ + const SKP_int16 x[] /* I Speech signal */ +); + +void SKP_Silk_find_pred_coefs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const SKP_int16 res_pitch[] /* I Residual from pitch analysis */ +); + +void SKP_Silk_find_LPC_FIX( + SKP_int NLSF_Q15[], /* O NLSFs */ + SKP_int *interpIndex, /* O NLSF interpolation index, only used for NLSF interpolation */ + const SKP_int prev_NLSFq_Q15[], /* I previous NLSFs, only used for NLSF interpolation */ + const SKP_int useInterpolatedLSFs, /* I Flag */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int16 x[], /* I Input signal */ + const SKP_int subfr_length /* I Input signal subframe length including preceeding samples */ +); + +void SKP_Silk_warped_LPC_analysis_filter_FIX( + SKP_int32 state[], /* I/O State [order + 1] */ + SKP_int16 res[], /* O Residual signal [length] */ + const SKP_int16 coef_Q13[], /* I Coefficients [order] */ + const SKP_int16 input[], /* I Input signal [length] */ + const SKP_int16 lambda_Q16, /* I Warping factor */ + const SKP_int length, /* I Length of input signal */ + const SKP_int order /* I Filter order (even) */ +); + +void SKP_Silk_LTP_analysis_filter_FIX( + SKP_int16 *LTP_res, /* O: LTP residual signal of length NB_SUBFR * ( pre_length + subfr_length ) */ + const SKP_int16 *x, /* I: Pointer to input signal with at least max( pitchL ) preceeding samples */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ],/* I: LTP_ORDER LTP coefficients for each NB_SUBFR subframe */ + const SKP_int pitchL[ NB_SUBFR ], /* I: Pitch lag, one for each subframe */ + const SKP_int32 invGains_Q16[ NB_SUBFR ], /* I: Inverse quantization gains, one for each subframe */ + const SKP_int subfr_length, /* I: Length of each subframe */ + const SKP_int pre_length /* I: Length of the preceeding samples starting at &x[0] for each subframe */ +); + +/* Finds LTP vector from correlations */ +void SKP_Silk_find_LTP_FIX( + SKP_int16 b_Q14[ NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + SKP_int32 WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + SKP_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const SKP_int16 r_first[], /* I residual signal after LPC signal + state for first 10 ms */ + const SKP_int16 r_last[], /* I residual signal after LPC signal + state for last 10 ms */ + const SKP_int lag[ NB_SUBFR ], /* I LTP lags */ + const SKP_int32 Wght_Q15[ NB_SUBFR ], /* I weights */ + const SKP_int subfr_length, /* I subframe length */ + const SKP_int mem_offset, /* I number of samples in LTP memory */ + SKP_int corr_rshifts[ NB_SUBFR ] /* O right shifts applied to correlations */ +); + +/* LTP tap quantizer */ +void SKP_Silk_quant_LTP_gains_FIX( + SKP_int16 B_Q14[], /* I/O (un)quantized LTP gains */ + SKP_int cbk_index[], /* O Codebook Index */ + SKP_int *periodicity_index, /* O Periodicity Index */ + const SKP_int32 W_Q18[], /* I Error Weights in Q18 */ + SKP_int mu_Q8, /* I Mu value (R/D tradeoff) */ + SKP_int lowComplexity /* I Flag for low complexity */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ + +/* Limit, stabilize, convert and quantize NLSFs. */ +void SKP_Silk_process_NLSFs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + SKP_int *pNLSF_Q15 /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ +); + +/* NLSF vector encoder */ +void SKP_Silk_NLSF_MSVQ_encode_FIX( + SKP_int *NLSFIndices, /* O Codebook path vector [ CB_STAGES ] */ + SKP_int *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const SKP_int *pNLSF_q_Q15_prev, /* I Prev. quantized NLSF vector [LPC_ORDER] */ + const SKP_int *pW_Q6, /* I NLSF weight vector [ LPC_ORDER ] */ + const SKP_int NLSF_mu_Q15, /* I Rate weight for the RD optimization */ + const SKP_int NLSF_mu_fluc_red_Q16, /* I Fluctuation reduction error weight */ + const SKP_int NLSF_MSVQ_Survivors, /* I Max survivors from each stage */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int deactivate_fluc_red /* I Deactivate fluctuation reduction */ +); + +/* Rate-Distortion calculations for multiple input data vectors */ +void SKP_Silk_NLSF_VQ_rate_distortion_FIX( + SKP_int32 *pRD_Q20, /* O Rate-distortion values [psNLSF_CBS->nVectors*N] */ + const SKP_Silk_NLSF_CBS *psNLSF_CBS, /* I NLSF codebook stage struct */ + const SKP_int *in_Q15, /* I Input vectors to be quantized */ + const SKP_int *w_Q6, /* I Weight vector */ + const SKP_int32 *rate_acc_Q5, /* I Accumulated rates from previous stage */ + const SKP_int mu_Q15, /* I Weight between weighted error and rate */ + const SKP_int N, /* I Number of input vectors to be quantized */ + const SKP_int LPC_order /* I LPC order */ +); + +/* Compute weighted quantization errors for an LPC_order element input vector, over one codebook stage */ +void SKP_Silk_NLSF_VQ_sum_error_FIX( + SKP_int32 *err_Q20, /* O Weighted quantization errors [N*K] */ + const SKP_int *in_Q15, /* I Input vectors to be quantized [N*LPC_order] */ + const SKP_int *w_Q6, /* I Weighting vectors [N*LPC_order] */ + const SKP_int16 *pCB_Q15, /* I Codebook vectors [K*LPC_order] */ + const SKP_int N, /* I Number of input vectors */ + const SKP_int K, /* I Number of codebook vectors */ + const SKP_int LPC_order /* I Number of LPCs */ +); + +/* Entropy constrained MATRIX-weighted VQ, for a single input data vector */ +void SKP_Silk_VQ_WMat_EC_FIX( + SKP_int *ind, /* O index of best codebook vector */ + SKP_int32 *rate_dist_Q14, /* O best weighted quantization error + mu * rate*/ + const SKP_int16 *in_Q14, /* I input vector to be quantized */ + const SKP_int32 *W_Q18, /* I weighting matrix */ + const SKP_int16 *cb_Q14, /* I codebook */ + const SKP_int16 *cl_Q6, /* I code length for each codebook vector */ + const SKP_int mu_Q8, /* I tradeoff between weighted error and rate */ + SKP_int L /* I number of vectors in codebook */ +); + +/******************/ +/* Linear Algebra */ +/******************/ + +/* Calculates correlation matrix X'*X */ +void SKP_Silk_corrMatrix_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + const SKP_int head_room, /* I Desired headroom */ + SKP_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ]*/ + SKP_int *rshifts /* I/O Right shifts of correlations */ +); + +/* Calculates correlation vector X'*t */ +void SKP_Silk_corrVector_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int16 *t, /* I Target vector [L] */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + SKP_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const SKP_int rshifts /* I Right shifts of correlations */ +); + +/* Add noise to matrix diagonal */ +void SKP_Silk_regularize_correlations_FIX( + SKP_int32 *XX, /* I/O Correlation matrices */ + SKP_int32 *xx, /* I/O Correlation values */ + SKP_int32 noise, /* I Noise to add */ + SKP_int D /* I Dimension of XX */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void SKP_Silk_solve_LDL_FIX( + SKP_int32 *A, /* I Pointer to symetric square matrix A */ + SKP_int M, /* I Size of matrix */ + const SKP_int32 *b, /* I Pointer to b vector */ + SKP_int32 *x_Q16 /* O Pointer to x solution vector */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +SKP_int32 SKP_Silk_residual_energy16_covar_FIX( + const SKP_int16 *c, /* I Prediction vector */ + const SKP_int32 *wXX, /* I Correlation matrix */ + const SKP_int32 *wXx, /* I Correlation vector */ + SKP_int32 wxx, /* I Signal energy */ + SKP_int D, /* I Dimension */ + SKP_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void SKP_Silk_residual_energy_FIX( + SKP_int32 nrgs[ NB_SUBFR ], /* O Residual energy per subframe */ + SKP_int nrgsQ[ NB_SUBFR ], /* O Q value per subframe */ + const SKP_int16 x[], /* I Input signal */ + SKP_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ],/* I AR coefs for each frame half */ + const SKP_int32 gains[ NB_SUBFR ], /* I Quantization gains */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int LPC_order /* I LPC order */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SKP_SILK_MAIN_FIX_H */ diff --git a/pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c b/pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c new file mode 100644 index 0000000..459cc69 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c @@ -0,0 +1,477 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_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.) */ +SKP_INLINE SKP_int32 warped_gain( // gain in Q16 + const SKP_int32 *coefs_Q24, + SKP_int lambda_Q16, + SKP_int order +) { + SKP_int i; + SKP_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = SKP_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return SKP_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 */ +SKP_INLINE void limit_warped_coefs( + SKP_int32 *coefs_syn_Q24, + SKP_int32 *coefs_ana_Q24, + SKP_int lambda_Q16, + SKP_int32 limit_Q24, + SKP_int order +) { + SKP_int i, iter, ind = 0; + SKP_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16; + SKP_int32 nom_Q16, den_Q24; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_syn_Q24[ i - 1 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = SKP_max( SKP_abs_int32( coefs_syn_Q24[ i ] ), SKP_abs_int32( coefs_ana_Q24[ i ] ) ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + if( maxabs_Q24 <= limit_Q24 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_syn_Q24[ i - 1 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + gain_syn_Q16 = SKP_INVERSE32_varQ( gain_syn_Q16, 32 ); + gain_ana_Q16 = SKP_INVERSE32_varQ( gain_ana_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SKP_FIX_CONST( 0.99, 16 ) - SKP_DIV32_varQ( + SKP_SMULWB( maxabs_Q24 - limit_Q24, SKP_SMLABB( SKP_FIX_CONST( 0.8, 10 ), SKP_FIX_CONST( 0.1, 10 ), iter ) ), + SKP_MUL( maxabs_Q24, ind + 1 ), 22 ); + SKP_Silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); + SKP_Silk_bwexpander_32( coefs_ana_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_syn_Q24[ i - 1 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + } + SKP_assert( 0 ); +} + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +void SKP_Silk_noise_shape_analysis_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const SKP_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const SKP_int16 *x /* I Input signal [ frame_length + la_shape ] */ +) +{ + SKP_Silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + SKP_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + SKP_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + SKP_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + SKP_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + SKP_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + SKP_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + SKP_int16 x_windowed[ SHAPE_LPC_WIN_MAX ]; + const SKP_int16 *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* CONTROL SNR */ + /****************/ + /* Reduce SNR_dB values if recent bitstream has exceeded TargetRate */ + psEncCtrl->current_SNR_dB_Q7 = psEnc->SNR_dB_Q7 - SKP_SMULWB( SKP_LSHIFT( ( SKP_int32 )psEnc->BufferedInChannel_ms, 7 ), + SKP_FIX_CONST( 0.05, 16 ) ); + + /* Reduce SNR_dB if inband FEC used */ + if( psEnc->speech_activity_Q8 > SKP_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEncCtrl->current_SNR_dB_Q7 -= SKP_RSHIFT( psEnc->inBandFEC_SNR_comp_Q8, 1 ); + } + + /****************/ + /* GAIN CONTROL */ + /****************/ + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( SKP_int )SKP_RSHIFT( ( SKP_int32 )psEncCtrl->input_quality_bands_Q15[ 0 ] + + psEncCtrl->input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->current_SNR_dB_Q7 - + SKP_FIX_CONST( 18.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + b_Q8 = SKP_FIX_CONST( 1.0, 8 ) - psEnc->speech_activity_Q8; + b_Q8 = SKP_SMULWB( SKP_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = SKP_SMLAWB( psEncCtrl->current_SNR_dB_Q7, + SKP_SMULBB( SKP_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), // Q11 + SKP_SMULWB( SKP_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); // Q12 + + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_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 = SKP_SMLAWB( SNR_adj_dB_Q7, + SKP_SMLAWB( SKP_FIX_CONST( 6.0, 9 ), -SKP_FIX_CONST( 0.4, 18 ), psEncCtrl->current_SNR_dB_Q7 ), + SKP_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Initally set to 0; may be overruled in process_gains(..) */ + psEncCtrl->sCmn.QuantOffsetType = 0; + psEncCtrl->sparseness_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = SKP_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < FRAME_LENGTH_MS / 2; k++ ) { + SKP_Silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += SKP_RSHIFT( nSamples, scale ); // Q(-scale) + + log_energy_Q7 = SKP_Silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += SKP_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_SMULWB( energy_variation_Q7 - + SKP_FIX_CONST( 5.0, 7 ), SKP_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SKP_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEncCtrl->sCmn.QuantOffsetType = 0; + } else { + psEncCtrl->sCmn.QuantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SKP_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = SKP_SMULWB( psEncCtrl->predGain_Q16, SKP_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = SKP_DIV32_varQ( SKP_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + SKP_SMLAWW( SKP_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = SKP_SMULWB( SKP_FIX_CONST( 1.0, 16 ) - SKP_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SKP_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = SKP_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = SKP_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = SKP_DIV32_16( SKP_LSHIFT( BWExp1_Q16, 14 ), SKP_RSHIFT( BWExp2_Q16, 2 ) ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = SKP_SMLAWB( psEnc->sCmn.warping_Q16, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < NB_SUBFR; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + SKP_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 5; + slope_part = SKP_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + SKP_Silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + SKP_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(SKP_int16) ); + shift += flat_part; + SKP_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 */ + SKP_Silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + SKP_Silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = SKP_ADD32( auto_corr[0], SKP_max_32( SKP_SMULWB( SKP_RSHIFT( auto_corr[ 0 ], 4 ), + SKP_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = SKP_Silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + SKP_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + SKP_Silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; // range: -12...30 + SKP_assert( Qnrg >= -12 ); + SKP_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = SKP_Silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; // range: -6...15 + + psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + SKP_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + if( psEncCtrl->Gains_Q16[ k ] < 0 ) { + psEncCtrl->Gains_Q16[ k ] = SKP_int32_MAX; + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + SKP_Silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + SKP_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( SKP_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + SKP_assert( BWExp1_Q16 <= SKP_FIX_CONST( 1.0, 16 ) ); + SKP_Silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + SKP_Silk_LPC_inverse_pred_gain_Q24( &pre_nrg_Q30, AR2_Q24, psEnc->sCmn.shapingLPCOrder ); + SKP_Silk_LPC_inverse_pred_gain_Q24( &nrg, AR1_Q24, psEnc->sCmn.shapingLPCOrder ); + + //psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg; + pre_nrg_Q30 = SKP_LSHIFT32( SKP_SMULWB( pre_nrg_Q30, SKP_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( SKP_int ) SKP_FIX_CONST( 0.3, 14 ) + SKP_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SKP_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = SKP_Silk_log2lin( -SKP_SMLAWB( -SKP_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SKP_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = SKP_Silk_log2lin( SKP_SMLAWB( SKP_FIX_CONST( 16.0, 7 ), SKP_FIX_CONST( NOISE_FLOOR_dB, 7 ), SKP_FIX_CONST( 0.16, 16 ) ) ); + tmp32 = SKP_Silk_log2lin( SKP_SMLAWB( SKP_FIX_CONST( 16.0, 7 ), SKP_FIX_CONST( RELATIVE_MIN_GAIN_dB, 7 ), SKP_FIX_CONST( 0.16, 16 ) ) ); + tmp32 = SKP_SMULWW( psEnc->avgGain_Q16, tmp32 ); + gain_add_Q16 = SKP_ADD_SAT32( gain_add_Q16, tmp32 ); + SKP_assert( gain_mult_Q16 >= 0 ); + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + if( psEncCtrl->Gains_Q16[ k ] < 0 ) { + psEncCtrl->Gains_Q16[ k ] = SKP_int32_MAX; + } + } + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains_Q16[ k ] = SKP_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + psEnc->avgGain_Q16 = SKP_ADD_SAT32( + psEnc->avgGain_Q16, + SKP_SMULWB( + psEncCtrl->Gains_Q16[ k ] - psEnc->avgGain_Q16, + SKP_RSHIFT_ROUND( SKP_SMULBB( psEnc->speech_activity_Q8, SKP_FIX_CONST( GAIN_SMOOTHING_COEF, 10 ) ), 2 ) + ) ); + } + + /************************************************/ + /* Decrease level during fricatives (de-essing) */ + /************************************************/ + gain_mult_Q16 = SKP_FIX_CONST( 1.0, 16 ) + SKP_RSHIFT_ROUND( SKP_MLA( SKP_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + + if( psEncCtrl->input_tilt_Q15 <= 0 && psEncCtrl->sCmn.sigtype == SIG_TYPE_UNVOICED ) { + if( psEnc->sCmn.fs_kHz == 24 ) { + SKP_int32 essStrength_Q15 = SKP_SMULWW( -psEncCtrl->input_tilt_Q15, + SKP_SMULBB( psEnc->speech_activity_Q8, SKP_FIX_CONST( 1.0, 8 ) - psEncCtrl->sparseness_Q8 ) ); + tmp32 = SKP_Silk_log2lin( SKP_FIX_CONST( 16.0, 7 ) - SKP_SMULWB( essStrength_Q15, + SKP_SMULWB( SKP_FIX_CONST( DE_ESSER_COEF_SWB_dB, 7 ), SKP_FIX_CONST( 0.16, 17 ) ) ) ); + gain_mult_Q16 = SKP_SMULWW( gain_mult_Q16, tmp32 ); + } else if( psEnc->sCmn.fs_kHz == 16 ) { + SKP_int32 essStrength_Q15 = SKP_SMULWW(-psEncCtrl->input_tilt_Q15, + SKP_SMULBB( psEnc->speech_activity_Q8, SKP_FIX_CONST( 1.0, 8 ) - psEncCtrl->sparseness_Q8 )); + tmp32 = SKP_Silk_log2lin( SKP_FIX_CONST( 16.0, 7 ) - SKP_SMULWB( essStrength_Q15, + SKP_SMULWB( SKP_FIX_CONST( DE_ESSER_COEF_WB_dB, 7 ), SKP_FIX_CONST( 0.16, 17 ) ) ) ); + gain_mult_Q16 = SKP_SMULWW( gain_mult_Q16, tmp32 ); + } else { + SKP_assert( psEnc->sCmn.fs_kHz == 12 || psEnc->sCmn.fs_kHz == 8 ); + } + } + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = SKP_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = SKP_MUL( SKP_FIX_CONST( LOW_FREQ_SHAPING, 0 ), SKP_FIX_CONST( 1.0, 16 ) + + SKP_SMULBB( SKP_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 1 ), psEncCtrl->input_quality_bands_Q15[ 0 ] - SKP_FIX_CONST( 1.0, 15 ) ) ); + if( psEncCtrl->sCmn.sigtype == SIG_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])*/ + SKP_int fs_kHz_inv = SKP_DIV32_16( SKP_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < NB_SUBFR; k++ ) { + b_Q14 = fs_kHz_inv + SKP_DIV32_16( SKP_FIX_CONST( 3.0, 14 ), psEncCtrl->sCmn.pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = SKP_LSHIFT( SKP_FIX_CONST( 1.0, 14 ) - b_Q14 - SKP_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (SKP_uint16)( b_Q14 - SKP_FIX_CONST( 1.0, 14 ) ); + } + SKP_assert( SKP_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SKP_FIX_CONST( 0.5, 24 ) ); // Guarantees that second argument to SMULWB() is within range of an SKP_int16 + Tilt_Q16 = - SKP_FIX_CONST( HP_NOISE_COEF, 16 ) - + SKP_SMULWB( SKP_FIX_CONST( 1.0, 16 ) - SKP_FIX_CONST( HP_NOISE_COEF, 16 ), + SKP_SMULWB( SKP_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->speech_activity_Q8 ) ); + } else { + b_Q14 = SKP_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); // 1.3_Q0 = 21299_Q14 + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = SKP_LSHIFT( SKP_FIX_CONST( 1.0, 14 ) - b_Q14 - + SKP_SMULWB( strength_Q16, SKP_SMULWB( SKP_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (SKP_uint16)( b_Q14 - SKP_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < NB_SUBFR; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SKP_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = SKP_SMULWB( SKP_SMULWB( SKP_FIX_CONST( 1.0, 17 ) - SKP_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SKP_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = SKP_SMLAWB( HarmBoost_Q16, + SKP_FIX_CONST( 1.0, 16 ) - SKP_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SKP_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = SKP_SMLAWB( SKP_FIX_CONST( HARMONIC_SHAPING, 16 ), + SKP_FIX_CONST( 1.0, 16 ) - SKP_SMULWB( SKP_FIX_CONST( 1.0, 18 ) - SKP_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SKP_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = SKP_SMULWB( SKP_LSHIFT( HarmShapeGain_Q16, 1 ), + SKP_Silk_SQRT_APPROX( SKP_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + SKP_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SKP_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + SKP_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SKP_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + SKP_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SKP_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( SKP_int )SKP_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( SKP_int )SKP_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( SKP_int )SKP_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c b/pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c new file mode 100644 index 0000000..7000ff4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c @@ -0,0 +1,706 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_pitch_est_defines.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +void SKP_FIX_P_Ana_calc_corr_st3( + SKP_int32 cross_corr_st3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX][PITCH_EST_NB_STAGE3_LAGS],/* (O) 3 DIM correlation array */ + const SKP_int16 signal[], /* I vector to correlate */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of a 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +); + +void SKP_FIX_P_Ana_calc_energy_st3( + SKP_int32 energies_st3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX][PITCH_EST_NB_STAGE3_LAGS],/* (O) 3 DIM energy array */ + const SKP_int16 signal[], /* I vector to calc energy in */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of one 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +); + +SKP_int32 SKP_FIX_P_Ana_find_scaling( + const SKP_int16 *signal, + const SKP_int signal_length, + const SKP_int sum_sqr_len +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +SKP_int SKP_Silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const SKP_int16 *signal, /* I Signal of length PITCH_EST_FRAME_LENGTH_MS*Fs_kHz */ + SKP_int *pitch_out, /* O 4 pitch lag values */ + SKP_int *lagIndex, /* O Lag Index */ + SKP_int *contourIndex, /* O Pitch contour Index */ + SKP_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + SKP_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const SKP_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const SKP_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const SKP_int Fs_kHz, /* I Sample frequency (kHz) */ + const SKP_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const SKP_int forLJC /* I 1 if this function is called from LJC code, 0 otherwise. */ +) +{ + SKP_int16 signal_8kHz[ PITCH_EST_MAX_FRAME_LENGTH_ST_2 ]; + SKP_int16 signal_4kHz[ PITCH_EST_MAX_FRAME_LENGTH_ST_1 ]; + SKP_int32 scratch_mem[ 3 * PITCH_EST_MAX_FRAME_LENGTH ]; + SKP_int16 *input_signal_ptr; + SKP_int32 filt_state[ PITCH_EST_MAX_DECIMATE_STATE_LENGTH ]; + SKP_int i, k, d, j; + SKP_int16 C[ PITCH_EST_NB_SUBFR ][ ( PITCH_EST_MAX_LAG >> 1 ) + 5 ]; + const SKP_int16 *target_ptr, *basis_ptr; + SKP_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target; + SKP_int d_srch[ PITCH_EST_D_SRCH_LENGTH ]; + SKP_int16 d_comp[ ( PITCH_EST_MAX_LAG >> 1 ) + 5 ]; + SKP_int Cmax, length_d_srch, length_d_comp; + SKP_int32 sum, threshold, temp32; + SKP_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + SKP_int32 CC[ PITCH_EST_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + SKP_int32 energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ]; + SKP_int32 crosscorr_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ]; + SKP_int32 lag_counter; + SKP_int frame_length, frame_length_8kHz, frame_length_4kHz, max_sum_sq_length; + SKP_int sf_length, sf_length_8kHz; + SKP_int min_lag, min_lag_8kHz, min_lag_4kHz; + SKP_int max_lag, max_lag_8kHz, max_lag_4kHz; + SKP_int32 contour_bias, diff; + SKP_int32 lz, lshift; + SKP_int cbk_offset, cbk_size, nb_cbks_stage2; + SKP_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q15, corr_thres_Q15; + + /* Check for valid sampling frequency */ + SKP_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 || Fs_kHz == 24 ); + + /* Check for valid complexity setting */ + SKP_assert( complexity >= SKP_Silk_PITCH_EST_MIN_COMPLEX ); + SKP_assert( complexity <= SKP_Silk_PITCH_EST_MAX_COMPLEX ); + + SKP_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + SKP_assert( search_thres2_Q15 >= 0 && search_thres2_Q15 <= (1<<15) ); + + /* Setup frame lengths max / min lag for the sampling frequency */ + frame_length = PITCH_EST_FRAME_LENGTH_MS * Fs_kHz; + frame_length_4kHz = PITCH_EST_FRAME_LENGTH_MS * 4; + frame_length_8kHz = PITCH_EST_FRAME_LENGTH_MS * 8; + sf_length = SKP_RSHIFT( frame_length, 3 ); + sf_length_8kHz = SKP_RSHIFT( frame_length_8kHz, 3 ); + min_lag = PITCH_EST_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PITCH_EST_MIN_LAG_MS * 4; + min_lag_8kHz = PITCH_EST_MIN_LAG_MS * 8; + max_lag = PITCH_EST_MAX_LAG_MS * Fs_kHz; + max_lag_4kHz = PITCH_EST_MAX_LAG_MS * 4; + max_lag_8kHz = PITCH_EST_MAX_LAG_MS * 8; + + SKP_memset( C, 0, sizeof( SKP_int16 ) * PITCH_EST_NB_SUBFR * ( ( PITCH_EST_MAX_LAG >> 1 ) + 5) ); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + SKP_memset( filt_state, 0, 2 * sizeof( SKP_int32 ) ); + SKP_Silk_resampler_down2( filt_state, signal_8kHz, signal, frame_length ); + } else if ( Fs_kHz == 12 ) { + SKP_int32 R23[ 6 ]; + SKP_memset( R23, 0, 6 * sizeof( SKP_int32 ) ); + SKP_Silk_resampler_down2_3( R23, signal_8kHz, signal, PITCH_EST_FRAME_LENGTH_MS * 12 ); + } else if( Fs_kHz == 24 ) { + SKP_int32 filt_state_fix[ 8 ]; + SKP_memset( filt_state_fix, 0, 8 * sizeof(SKP_int32) ); + SKP_Silk_resampler_down3( filt_state_fix, signal_8kHz, signal, 24 * PITCH_EST_FRAME_LENGTH_MS ); + } else { + SKP_assert( Fs_kHz == 8 ); + SKP_memcpy( signal_8kHz, signal, frame_length_8kHz * sizeof(SKP_int16) ); + } + /* Decimate again to 4 kHz */ + SKP_memset( filt_state, 0, 2 * sizeof( SKP_int32 ) );/* Set state to zero */ + SKP_Silk_resampler_down2( filt_state, signal_4kHz, signal_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + signal_4kHz[ i ] = SKP_ADD_SAT16( signal_4kHz[ i ], signal_4kHz[ i - 1 ] ); + } + + /******************************************************************************* + ** Scale 4 kHz signal down to prevent correlations measures from overflowing + ** find scaling as max scaling for each 8kHz(?) subframe + *******************************************************************************/ + + /* Inner product is calculated with different lengths, so scale for the worst case */ + max_sum_sq_length = SKP_max_32( sf_length_8kHz, SKP_RSHIFT( frame_length_4kHz, 1 ) ); + shift = SKP_FIX_P_Ana_find_scaling( signal_4kHz, frame_length_4kHz, max_sum_sq_length ); + if( shift > 0 ) { + for( i = 0; i < frame_length_4kHz; i++ ) { + signal_4kHz[ i ] = SKP_RSHIFT( signal_4kHz[ i ], shift ); + } + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + target_ptr = &signal_4kHz[ SKP_RSHIFT( frame_length_4kHz, 1 ) ]; + for( k = 0; k < 2; k++ ) { + /* Check that we are within range of the array */ + SKP_assert( target_ptr >= signal_4kHz ); + SKP_assert( target_ptr + sf_length_8kHz <= signal_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + SKP_assert( basis_ptr >= signal_4kHz ); + SKP_assert( basis_ptr + sf_length_8kHz <= signal_4kHz + frame_length_4kHz ); + + normalizer = 0; + cross_corr = 0; + /* Calculate first vector products before loop */ + cross_corr = SKP_Silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = SKP_Silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + normalizer = SKP_ADD_SAT32( normalizer, SKP_SMULBB( sf_length_8kHz, 4000 ) ); + + temp32 = SKP_DIV32( cross_corr, SKP_Silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ min_lag_4kHz ] = (SKP_int16)SKP_SAT16( temp32 ); /* Q0 */ + + /* 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 */ + SKP_assert( basis_ptr >= signal_4kHz ); + SKP_assert( basis_ptr + sf_length_8kHz <= signal_4kHz + frame_length_4kHz ); + + cross_corr = SKP_Silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + SKP_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + SKP_SMULBB( basis_ptr[ sf_length_8kHz ], basis_ptr[ sf_length_8kHz ] ); + + temp32 = SKP_DIV32( cross_corr, SKP_Silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ d ] = (SKP_int16)SKP_SAT16( temp32 ); /* Q0 */ + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + sum = (SKP_int32)C[ 0 ][ i ] + (SKP_int32)C[ 1 ][ i ]; /* Q0 */ + SKP_assert( SKP_RSHIFT( sum, 1 ) == SKP_SAT16( SKP_RSHIFT( sum, 1 ) ) ); + sum = SKP_RSHIFT( sum, 1 ); /* Q-1 */ + SKP_assert( SKP_LSHIFT( (SKP_int32)-i, 4 ) == SKP_SAT16( SKP_LSHIFT( (SKP_int32)-i, 4 ) ) ); + sum = SKP_SMLAWB( sum, sum, SKP_LSHIFT( -i, 4 ) ); /* Q-1 */ + SKP_assert( sum == SKP_SAT16( sum ) ); + C[ 0 ][ i ] = (SKP_int16)sum; /* Q-1 */ + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + SKP_assert( 3 * length_d_srch <= PITCH_EST_D_SRCH_LENGTH ); + SKP_Silk_insertion_sort_decreasing_int16( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + target_ptr = &signal_4kHz[ SKP_RSHIFT( frame_length_4kHz, 1 ) ]; + energy = SKP_Silk_inner_prod_aligned( target_ptr, target_ptr, SKP_RSHIFT( frame_length_4kHz, 1 ) ); + energy = SKP_ADD_POS_SAT32( energy, 1000 ); /* Q0 */ + Cmax = (SKP_int)C[ 0 ][ min_lag_4kHz ]; /* Q-1 */ + threshold = SKP_SMULBB( Cmax, Cmax ); /* Q-2 */ + /* Compare in Q-2 domain */ + if( SKP_RSHIFT( energy, 4 + 2 ) > threshold ) { + SKP_memset( pitch_out, 0, PITCH_EST_NB_SUBFR * sizeof( SKP_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = SKP_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[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = ( d_srch[ i ] + min_lag_4kHz ) << 1; + } else { + length_d_srch = i; + break; + } + } + SKP_assert( length_d_srch > 0 ); + + for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) { + d_comp[ i ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] ] = 1; + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ]; + } + + length_d_srch = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) { + if( d_comp[ i + 1 ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) { + d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ]; + } + + length_d_comp = 0; + for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) { + if( d_comp[ i ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + + /****************************************************************************** + ** Scale signal down to avoid correlations measures from overflowing + *******************************************************************************/ + /* find scaling as max scaling for each subframe */ + shift = SKP_FIX_P_Ana_find_scaling( signal_8kHz, frame_length_8kHz, sf_length_8kHz ); + if( shift > 0 ) { + for( i = 0; i < frame_length_8kHz; i++ ) { + signal_8kHz[ i ] = SKP_RSHIFT( signal_8kHz[ i ], shift ); + } + } + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + SKP_memset( C, 0, PITCH_EST_NB_SUBFR * ( ( PITCH_EST_MAX_LAG >> 1 ) + 5 ) * sizeof( SKP_int16 ) ); + + target_ptr = &signal_8kHz[ frame_length_4kHz ]; /* point to middle of frame */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + + /* Check that we are within range of the array */ + SKP_assert( target_ptr >= signal_8kHz ); + SKP_assert( target_ptr + sf_length_8kHz <= signal_8kHz + frame_length_8kHz ); + + energy_target = SKP_Silk_inner_prod_aligned( target_ptr, target_ptr, sf_length_8kHz ); + // ToDo: Calculate 1 / energy_target here and save one division inside next for loop + 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 */ + SKP_assert( basis_ptr >= signal_8kHz ); + SKP_assert( basis_ptr + sf_length_8kHz <= signal_8kHz + frame_length_8kHz ); + + cross_corr = SKP_Silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + energy_basis = SKP_Silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + if( cross_corr > 0 ) { + energy = SKP_max( energy_target, energy_basis ); /* Find max to make sure first division < 1.0 */ + lz = SKP_Silk_CLZ32( cross_corr ); + lshift = SKP_LIMIT_32( lz - 1, 0, 15 ); + temp32 = SKP_DIV32( SKP_LSHIFT( cross_corr, lshift ), SKP_RSHIFT( energy, 15 - lshift ) + 1 ); /* Q15 */ + SKP_assert( temp32 == SKP_SAT16( temp32 ) ); + temp32 = SKP_SMULWB( cross_corr, temp32 ); /* Q(-1), cc * ( cc / max(b, t) ) */ + temp32 = SKP_ADD_SAT32( temp32, temp32 ); /* Q(0) */ + lz = SKP_Silk_CLZ32( temp32 ); + lshift = SKP_LIMIT_32( lz - 1, 0, 15 ); + energy = SKP_min( energy_target, energy_basis ); + C[ k ][ d ] = SKP_DIV32( SKP_LSHIFT( temp32, lshift ), SKP_RSHIFT( energy, 15 - lshift ) + 1 ); // Q15 + } else { + C[ k ][ d ] = 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 = SKP_int32_MIN; + CCmax_b = SKP_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 = SKP_DIV32_16( SKP_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = SKP_RSHIFT( prevLag, 1 ); + } else if( Fs_kHz == 24 ) { + prevLag = SKP_DIV32_16( prevLag, 3 ); + } + prevLag_log2_Q7 = SKP_Silk_lin2log( (SKP_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + SKP_assert( search_thres2_Q15 == SKP_SAT16( search_thres2_Q15 ) ); + corr_thres_Q15 = SKP_RSHIFT( SKP_SMULBB( search_thres2_Q15, search_thres2_Q15 ), 13 ); + + /* If input is 8 khz use a larger codebook here because it is last stage */ + if( Fs_kHz == 8 && complexity > SKP_Silk_PITCH_EST_MIN_COMPLEX ) { + nb_cbks_stage2 = PITCH_EST_NB_CBKS_STAGE2_EXT; + } else { + nb_cbks_stage2 = PITCH_EST_NB_CBKS_STAGE2; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbks_stage2; j++ ) { + CC[ j ] = 0; + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + /* Try all codebooks */ + CC[ j ] = CC[ j ] + (SKP_int32)C[ i ][ d + SKP_Silk_CB_lags_stage2[ i ][ j ] ]; + } + } + /* Find best codebook */ + CCmax_new = SKP_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbks_stage2; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = SKP_Silk_lin2log( (SKP_int32)d ); /* Q7 */ + SKP_assert( lag_log2_Q7 == SKP_SAT16( lag_log2_Q7 ) ); + SKP_assert( PITCH_EST_NB_SUBFR * PITCH_EST_SHORTLAG_BIAS_Q15 == SKP_SAT16( PITCH_EST_NB_SUBFR * PITCH_EST_SHORTLAG_BIAS_Q15 ) ); + + if (forLJC) { + CCmax_new_b = CCmax_new; + } else { + CCmax_new_b = CCmax_new - SKP_RSHIFT( SKP_SMULBB( PITCH_EST_NB_SUBFR * PITCH_EST_SHORTLAG_BIAS_Q15, lag_log2_Q7 ), 7 ); /* Q15 */ + } + + /* Bias towards previous lag */ + SKP_assert( PITCH_EST_NB_SUBFR * PITCH_EST_PREVLAG_BIAS_Q15 == SKP_SAT16( PITCH_EST_NB_SUBFR * PITCH_EST_PREVLAG_BIAS_Q15 ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + SKP_assert( delta_lag_log2_sqr_Q7 == SKP_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = SKP_RSHIFT( SKP_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q15 = SKP_RSHIFT( SKP_SMULBB( PITCH_EST_NB_SUBFR * PITCH_EST_PREVLAG_BIAS_Q15, ( *LTPCorr_Q15 ) ), 15 ); /* Q15 */ + prev_lag_bias_Q15 = SKP_DIV32( SKP_MUL( prev_lag_bias_Q15, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + ( 1 << 6 ) ); + CCmax_new_b -= prev_lag_bias_Q15; /* Q15 */ + } + + if ( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > corr_thres_Q15 && /* Correlation needs to be high enough to be voiced */ + SKP_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 */ + SKP_memset( pitch_out, 0, PITCH_EST_NB_SUBFR * sizeof( SKP_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + if( Fs_kHz > 8 ) { + + /****************************************************************************** + ** Scale input signal down to avoid correlations measures from overflowing + *******************************************************************************/ + /* find scaling as max scaling for each subframe */ + shift = SKP_FIX_P_Ana_find_scaling( signal, frame_length, sf_length ); + if( shift > 0 ) { + /* Move signal to scratch mem because the input signal should be unchanged */ + /* Reuse the 32 bit scratch mem vector, use a 16 bit pointer from now */ + input_signal_ptr = (SKP_int16*)scratch_mem; + for( i = 0; i < frame_length; i++ ) { + input_signal_ptr[ i ] = SKP_RSHIFT( signal[ i ], shift ); + } + } else { + input_signal_ptr = (SKP_int16*)signal; + } + /*********************************************************************************/ + + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + SKP_assert( lag == SKP_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = SKP_RSHIFT( SKP_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = SKP_LSHIFT( lag, 1 ); + } else { + lag = SKP_SMULBB( lag, 3 ); + } + + lag = SKP_LIMIT_int( lag, min_lag, max_lag ); + start_lag = SKP_max_int( lag - 2, min_lag ); + end_lag = SKP_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + SKP_assert( SKP_LSHIFT( CCmax, 13 ) >= 0 ); + *LTPCorr_Q15 = (SKP_int)SKP_Silk_SQRT_APPROX( SKP_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + + CCmax = SKP_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + pitch_out[ k ] = lag + 2 * SKP_Silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + /* Calculate the correlations and energies needed in stage 3 */ + SKP_FIX_P_Ana_calc_corr_st3( crosscorr_st3, input_signal_ptr, start_lag, sf_length, complexity ); + SKP_FIX_P_Ana_calc_energy_st3( energies_st3, input_signal_ptr, start_lag, sf_length, complexity ); + + lag_counter = 0; + SKP_assert( lag == SKP_SAT16( lag ) ); + contour_bias = SKP_DIV32_16( PITCH_EST_FLATCONTOUR_BIAS_Q20, lag ); + + /* Setup cbk parameters acording to complexity setting */ + cbk_size = (SKP_int)SKP_Silk_cbk_sizes_stage3[ complexity ]; + cbk_offset = (SKP_int)SKP_Silk_cbk_offsets_stage3[ complexity ]; + + for( d = start_lag; d <= end_lag; d++ ) { + for( j = cbk_offset; j < ( cbk_offset + cbk_size ); j++ ) { + cross_corr = 0; + energy = 0; + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + SKP_assert( PITCH_EST_NB_SUBFR == 4 ); + energy += SKP_RSHIFT( energies_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + SKP_assert( energy >= 0 ); + cross_corr += SKP_RSHIFT( crosscorr_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + } + if( cross_corr > 0 ) { + /* Divide cross_corr / energy and get result in Q15 */ + lz = SKP_Silk_CLZ32( cross_corr ); + /* Divide with result in Q13, cross_corr could be larger than energy */ + lshift = SKP_LIMIT_32( lz - 1, 0, 13 ); + CCmax_new = SKP_DIV32( SKP_LSHIFT( cross_corr, lshift ), SKP_RSHIFT( energy, 13 - lshift ) + 1 ); + CCmax_new = SKP_SAT16( CCmax_new ); + CCmax_new = SKP_SMULWB( cross_corr, CCmax_new ); + /* Saturate */ + if( CCmax_new > SKP_RSHIFT( SKP_int32_MAX, 3 ) ) { + CCmax_new = SKP_int32_MAX; + } else { + CCmax_new = SKP_LSHIFT( CCmax_new, 3 ); + } + /* Reduce depending on flatness of contour */ + diff = j - SKP_RSHIFT( PITCH_EST_NB_CBKS_STAGE3_MAX, 1 ); + diff = SKP_MUL( diff, diff ); + diff = SKP_int16_MAX - SKP_RSHIFT( SKP_MUL( contour_bias, diff ), 5 ); /* Q20 -> Q15 */ + SKP_assert( diff == SKP_SAT16( diff ) ); + CCmax_new = SKP_LSHIFT( SKP_SMULWB( CCmax_new, diff ), 1 ); + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && + ( d + (SKP_int)SKP_Silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag + ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + pitch_out[ k ] = lag_new + SKP_Silk_CB_lags_stage3[ k ][ CBimax ]; + } + *lagIndex = lag_new - min_lag; + *contourIndex = CBimax; + } else { + /* Save Lags and correlation */ + CCmax = SKP_max( CCmax, 0 ); + *LTPCorr_Q15 = (SKP_int)SKP_Silk_SQRT_APPROX( SKP_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + pitch_out[ k ] = lag + SKP_Silk_CB_lags_stage2[ k ][ CBimax ]; + } + *lagIndex = lag - min_lag_8kHz; + *contourIndex = CBimax; + } + SKP_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +/*************************************************************************/ +/* Calculates the correlations used in stage 3 search. In order to cover */ +/* the whole lag codebook for all the searched offset lags (lag +- 2), */ +/*************************************************************************/ +void SKP_FIX_P_Ana_calc_corr_st3( + SKP_int32 cross_corr_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ],/* (O) 3 DIM correlation array */ + const SKP_int16 signal[], /* I vector to correlate */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of a 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +) +{ + const SKP_int16 *target_ptr, *basis_ptr; + SKP_int32 cross_corr; + SKP_int i, j, k, lag_counter; + SKP_int cbk_offset, cbk_size, delta, idx; + SKP_int32 scratch_mem[ SCRATCH_SIZE ]; + + SKP_assert( complexity >= SKP_Silk_PITCH_EST_MIN_COMPLEX ); + SKP_assert( complexity <= SKP_Silk_PITCH_EST_MAX_COMPLEX ); + + cbk_offset = SKP_Silk_cbk_offsets_stage3[ complexity ]; + cbk_size = SKP_Silk_cbk_sizes_stage3[ complexity ]; + + target_ptr = &signal[ SKP_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + for( j = SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ]; j <= SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 1 ]; j++ ) { + basis_ptr = target_ptr - ( start_lag + j ); + cross_corr = SKP_Silk_inner_prod_aligned( (SKP_int16*)target_ptr, (SKP_int16*)basis_ptr, sf_length ); + SKP_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = cross_corr; + lag_counter++; + } + + delta = SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ]; + for( i = cbk_offset; i < ( cbk_offset + cbk_size ); i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = SKP_Silk_CB_lags_stage3[ k ][ i ] - delta; + for( j = 0; j < PITCH_EST_NB_STAGE3_LAGS; j++ ) { + SKP_assert( idx + j < SCRATCH_SIZE ); + SKP_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +void SKP_FIX_P_Ana_calc_energy_st3( + SKP_int32 energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ],/* (O) 3 DIM energy array */ + const SKP_int16 signal[], /* I vector to calc energy in */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of one 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +) +{ + const SKP_int16 *target_ptr, *basis_ptr; + SKP_int32 energy; + SKP_int k, i, j, lag_counter; + SKP_int cbk_offset, cbk_size, delta, idx; + SKP_int32 scratch_mem[ SCRATCH_SIZE ]; + + SKP_assert( complexity >= SKP_Silk_PITCH_EST_MIN_COMPLEX ); + SKP_assert( complexity <= SKP_Silk_PITCH_EST_MAX_COMPLEX ); + + cbk_offset = SKP_Silk_cbk_offsets_stage3[ complexity ]; + cbk_size = SKP_Silk_cbk_sizes_stage3[ complexity ]; + + target_ptr = &signal[ SKP_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ] ); + energy = SKP_Silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length ); + SKP_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + for( i = 1; i < ( SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 1 ] - SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ] + 1 ); i++ ) { + /* remove part outside new window */ + energy -= SKP_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + SKP_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = SKP_ADD_SAT32( energy, SKP_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + SKP_assert( energy >= 0 ); + SKP_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = SKP_Silk_Lag_range_stage3[ complexity ][ k ][ 0 ]; + for( i = cbk_offset; i < ( cbk_offset + cbk_size ); i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = SKP_Silk_CB_lags_stage3[ k ][ i ] - delta; + for( j = 0; j < PITCH_EST_NB_STAGE3_LAGS; j++ ) { + SKP_assert( idx + j < SCRATCH_SIZE ); + SKP_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + SKP_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} + +SKP_int32 SKP_FIX_P_Ana_find_scaling( + const SKP_int16 *signal, + const SKP_int signal_length, + const SKP_int sum_sqr_len +) +{ + SKP_int32 nbits, x_max; + + x_max = SKP_Silk_int16_array_maxabs( signal, signal_length ); + + if( x_max < SKP_int16_MAX ) { + /* Number of bits needed for the sum of the squares */ + nbits = 32 - SKP_Silk_CLZ32( SKP_SMULBB( x_max, x_max ) ); + } else { + /* Here we don't know if x_max should have been SKP_int16_MAX + 1, so we expect the worst case */ + nbits = 30; + } + nbits += 17 - SKP_Silk_CLZ16( sum_sqr_len ); + + /* Without a guarantee of saturation, we need to keep the 31st bit free */ + if( nbits < 31 ) { + return 0; + } else { + return( nbits - 30 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_pitch_est_defines.h b/pkg/silk/csilk/SKP_Silk_pitch_est_defines.h new file mode 100644 index 0000000..df299b4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_pitch_est_defines.h @@ -0,0 +1,40 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROCFIX_PITCH_EST_DEFINES_H +#define SIGPROCFIX_PITCH_EST_DEFINES_H + +/************************************************************/ +/* Definitions For Fix pitch estimator */ +/************************************************************/ + +#define PITCH_EST_SHORTLAG_BIAS_Q15 6554 /* 0.2f. for logarithmic weighting */ +#define PITCH_EST_PREVLAG_BIAS_Q15 6554 /* Prev lag bias */ +#define PITCH_EST_FLATCONTOUR_BIAS_Q20 52429 /* 0.05f */ + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_pitch_est_tables.c b/pkg/silk/csilk/SKP_Silk_pitch_est_tables.c new file mode 100644 index 0000000..26902b3 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_pitch_est_tables.c @@ -0,0 +1,89 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +/********************************************************/ +/* Auto Generated File from generate_pitch_est_tables.m */ +/********************************************************/ + +const SKP_int16 SKP_Silk_CB_lags_stage2[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE2_EXT] = +{ + {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1} +}; + +const SKP_int16 SKP_Silk_CB_lags_stage3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX] = +{ + {-9,-7,-6,-5,-5,-4,-4,-3,-3,-2,-2,-2,-1,-1,-1, 0, 0, 0, 1, 1, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, 5, 6, 8}, + {-3,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 2, 1, 2, 2, 2, 2, 3}, + { 3, 3, 2, 2, 2, 2, 1, 2, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,-1, 0, 0,-1,-1,-1,-1,-1,-2,-2,-2}, + { 9, 8, 6, 5, 6, 5, 4, 4, 3, 3, 2, 2, 2, 1, 0, 1, 1, 0, 0, 0,-1,-1,-1,-2,-2,-2,-3,-3,-4,-4,-5,-5,-6,-7} + }; + +const SKP_int16 SKP_Silk_Lag_range_stage3[ SKP_Silk_PITCH_EST_MAX_COMPLEX + 1 ] [ PITCH_EST_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-2,6}, + {-1,5}, + {-1,5}, + {-2,7} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-4,8}, + {-1,6}, + {-1,6}, + {-4,9} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const SKP_int16 SKP_Silk_cbk_sizes_stage3[SKP_Silk_PITCH_EST_MAX_COMPLEX + 1] = +{ + PITCH_EST_NB_CBKS_STAGE3_MIN, + PITCH_EST_NB_CBKS_STAGE3_MID, + PITCH_EST_NB_CBKS_STAGE3_MAX +}; + +const SKP_int16 SKP_Silk_cbk_offsets_stage3[SKP_Silk_PITCH_EST_MAX_COMPLEX + 1] = +{ + ((PITCH_EST_NB_CBKS_STAGE3_MAX - PITCH_EST_NB_CBKS_STAGE3_MIN) >> 1), + ((PITCH_EST_NB_CBKS_STAGE3_MAX - PITCH_EST_NB_CBKS_STAGE3_MID) >> 1), + 0 +}; + diff --git a/pkg/silk/csilk/SKP_Silk_prefilter_FIX.c b/pkg/silk/csilk/SKP_Silk_prefilter_FIX.c new file mode 100644 index 0000000..7b626b9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_prefilter_FIX.c @@ -0,0 +1,224 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* SKP_Silk_prefilter. Prefilter for finding Quantizer input signal */ +SKP_INLINE void SKP_Silk_prefilt_FIX( + SKP_Silk_prefilter_state_FIX *P, /* I/O state */ + SKP_int32 st_res_Q12[], /* I short term residual signal */ + SKP_int16 xw[], /* O prefiltered signal */ + SKP_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + SKP_int Tilt_Q14, /* I Tilt shaping coeficient */ + SKP_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients*/ + SKP_int lag, /* I Lag for harmonic shaping */ + SKP_int length /* I Length of signals */ +); +#if EMBEDDED_ARM<6 +void SKP_Silk_warped_LPC_analysis_filter_FIX( + SKP_int32 state[], /* I/O State [order + 1] */ + SKP_int16 res[], /* O Residual signal [length] */ + const SKP_int16 coef_Q13[], /* I Coefficients [order] */ + const SKP_int16 input[], /* I Input signal [length] */ + const SKP_int16 lambda_Q16, /* I Warping factor */ + const SKP_int length, /* I Length of input signal */ + const SKP_int order /* I Filter order (even) */ +) +{ + SKP_int n, i; + SKP_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + SKP_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = SKP_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = SKP_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = SKP_SMULWB( tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = SKP_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = SKP_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = SKP_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = SKP_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res[ n ] = ( SKP_int16 )SKP_SAT16( ( SKP_int32 )input[ n ] - SKP_RSHIFT_ROUND( acc_Q11, 11 ) ); + } +} +#endif + +void SKP_Silk_prefilter_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + const SKP_Silk_encoder_control_FIX *psEncCtrl, /* I Encoder control FIX */ + SKP_int16 xw[], /* O Weighted signal */ + const SKP_int16 x[] /* I Speech signal */ +) +{ + SKP_Silk_prefilter_state_FIX *P = &psEnc->sPrefilt; + SKP_int j, k, lag; + SKP_int32 tmp_32; + const SKP_int16 *AR1_shp_Q13; + const SKP_int16 *px; + SKP_int16 *pxw; + SKP_int HarmShapeGain_Q12, Tilt_Q14; + SKP_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14; + SKP_int32 x_filt_Q12[ MAX_FRAME_LENGTH / NB_SUBFR ]; + SKP_int16 st_res[ ( MAX_FRAME_LENGTH / NB_SUBFR ) + MAX_SHAPE_LPC_ORDER ]; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 B_Q12; +#else + SKP_int16 B_Q12[ 2 ]; +#endif + + /* Setup pointers */ + px = x; + pxw = xw; + lag = P->lagPrev; + for( k = 0; k < NB_SUBFR; k++ ) { + /* Update Variables that change per sub frame */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + lag = psEncCtrl->sCmn.pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain_Q12 = SKP_SMULWB( psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] ); + SKP_assert( HarmShapeGain_Q12 >= 0 ); + HarmShapeFIRPacked_Q12 = SKP_RSHIFT( HarmShapeGain_Q12, 2 ); + HarmShapeFIRPacked_Q12 |= SKP_LSHIFT( ( SKP_int32 )SKP_RSHIFT( HarmShapeGain_Q12, 1 ), 16 ); + Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ]; + LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ]; + AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering*/ + SKP_Silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res, AR1_shp_Q13, px, + psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* reduce (mainly) low frequencies during harmonic emphasis */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLABB and SMLABT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLABB and SMLABT instructions should solve the problem. */ + B_Q12 = SKP_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 2 ); + tmp_32 = SKP_SMLABB( SKP_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = SKP_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = SKP_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = SKP_RSHIFT_ROUND( tmp_32, 12 ); /* Q12 */ + B_Q12 |= SKP_LSHIFT( SKP_SAT16( tmp_32 ), 16 ); + + x_filt_Q12[ 0 ] = SKP_SMLABT( SKP_SMULBB( st_res[ 0 ], B_Q12 ), P->sHarmHP, B_Q12 ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = SKP_SMLABT( SKP_SMULBB( st_res[ j ], B_Q12 ), st_res[ j - 1 ], B_Q12 ); + } +#else + B_Q12[ 0 ] = SKP_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 2 ); + tmp_32 = SKP_SMLABB( SKP_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = SKP_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = SKP_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = SKP_RSHIFT_ROUND( tmp_32, 12 ); /* Q12 */ + B_Q12[ 1 ]= SKP_SAT16( tmp_32 ); + + x_filt_Q12[ 0 ] = SKP_SMLABB( SKP_SMULBB( st_res[ 0 ], B_Q12[ 0 ] ), P->sHarmHP, B_Q12[ 1 ] ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = SKP_SMLABB( SKP_SMULBB( st_res[ j ], B_Q12[ 0 ] ), st_res[ j - 1 ], B_Q12[ 1 ] ); + } +#endif + P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ]; + + SKP_Silk_prefilt_FIX( P, x_filt_Q12, pxw, HarmShapeFIRPacked_Q12, Tilt_Q14, + LF_shp_Q14, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw += psEnc->sCmn.subfr_length; + } + + P->lagPrev = psEncCtrl->sCmn.pitchL[ NB_SUBFR - 1 ]; +} + +/* SKP_Silk_prefilter. Prefilter for finding Quantizer input signal */ +SKP_INLINE void SKP_Silk_prefilt_FIX( + SKP_Silk_prefilter_state_FIX *P, /* I/O state */ + SKP_int32 st_res_Q12[], /* I short term residual signal */ + SKP_int16 xw[], /* O prefiltered signal */ + SKP_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + SKP_int Tilt_Q14, /* I Tilt shaping coeficient */ + SKP_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients*/ + SKP_int lag, /* I Lag for harmonic shaping */ + SKP_int length /* I Length of signals */ +) +{ + SKP_int i, idx, LTP_shp_buf_idx; + SKP_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + SKP_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + SKP_int16 *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12; + sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + /* unrolled loop */ + SKP_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = SKP_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = SKP_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = SKP_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + } else { + n_LTP_Q12 = 0; + } + + n_Tilt_Q10 = SKP_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = SKP_SMLAWB( SKP_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = SKP_SUB32( st_res_Q12[ i ], SKP_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = SKP_SUB32( sLF_AR_shp_Q12, SKP_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw[i] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 12 ) ); + } + + /* Copy temp variable back to state */ + P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12; + P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c b/pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c new file mode 100644 index 0000000..28b8e77 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c @@ -0,0 +1,127 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Limit, stabilize, convert and quantize NLSFs. */ +void SKP_Silk_process_NLSFs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + SKP_int *pNLSF_Q15 /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ +) +{ + SKP_int doInterpolate; + SKP_int pNLSFW_Q6[ MAX_LPC_ORDER ]; + SKP_int NLSF_mu_Q15, NLSF_mu_fluc_red_Q16; + SKP_int32 i_sqr_Q15; + const SKP_Silk_NLSF_CB_struct *psNLSF_CB; + + /* Used only for NLSF interpolation */ + SKP_int pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + SKP_int pNLSFW0_temp_Q6[ MAX_LPC_ORDER ]; + SKP_int i; + + SKP_assert( psEnc->speech_activity_Q8 >= 0 ); + SKP_assert( psEnc->speech_activity_Q8 <= 256 ); + SKP_assert( psEncCtrl->sparseness_Q8 >= 0 ); + SKP_assert( psEncCtrl->sparseness_Q8 <= 256 ); + SKP_assert( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED || psEncCtrl->sCmn.sigtype == SIG_TYPE_UNVOICED ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* NLSF_mu = 0.002f - 0.001f * psEnc->speech_activity; */ + /* NLSF_mu_fluc_red = 0.1f - 0.05f * psEnc->speech_activity; */ + NLSF_mu_Q15 = SKP_SMLAWB( 66, -8388, psEnc->speech_activity_Q8 ); + NLSF_mu_fluc_red_Q16 = SKP_SMLAWB( 6554, -838848, psEnc->speech_activity_Q8 ); + } else { + /* NLSF_mu = 0.005f - 0.004f * psEnc->speech_activity; */ + /* NLSF_mu_fluc_red = 0.2f - 0.1f * psEnc->speech_activity - 0.1f * psEncCtrl->sparseness; */ + NLSF_mu_Q15 = SKP_SMLAWB( 164, -33554, psEnc->speech_activity_Q8 ); + NLSF_mu_fluc_red_Q16 = SKP_SMLAWB( 13107, -1677696, psEnc->speech_activity_Q8 + psEncCtrl->sparseness_Q8 ); + } + SKP_assert( NLSF_mu_Q15 >= 0 ); + SKP_assert( NLSF_mu_Q15 <= 164 ); + SKP_assert( NLSF_mu_fluc_red_Q16 >= 0 ); + SKP_assert( NLSF_mu_fluc_red_Q16 <= 13107 ); + + NLSF_mu_Q15 = SKP_max( NLSF_mu_Q15, 1 ); + + /* Calculate NLSF weights */ + TIC(NLSF_weights_FIX) + SKP_Silk_NLSF_VQ_weights_laroia( pNLSFW_Q6, pNLSF_Q15, psEnc->sCmn.predictLPCOrder ); + TOC(NLSF_weights_FIX) + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEnc->sCmn.useInterpolatedNLSFs == 1 ) && ( psEncCtrl->sCmn.NLSFInterpCoef_Q2 < ( 1 << 2 ) ); + if( doInterpolate ) { + + /* Calculate the interpolated NLSF vector for the first half */ + SKP_Silk_interpolate( pNLSF0_temp_Q15, psEnc->sPred.prev_NLSFq_Q15, pNLSF_Q15, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sCmn.predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + TIC(NLSF_weights_FIX) + SKP_Silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_Q6, pNLSF0_temp_Q15, psEnc->sCmn.predictLPCOrder ); + TOC(NLSF_weights_FIX) + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = SKP_LSHIFT( SKP_SMULBB( psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->sCmn.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + pNLSFW_Q6[ i ] = SKP_SMLAWB( SKP_RSHIFT( pNLSFW_Q6[ i ], 1 ), pNLSFW0_temp_Q6[ i ], i_sqr_Q15 ); + SKP_assert( pNLSFW_Q6[ i ] <= SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ i ] >= 1 ); + } + } + + /* Set pointer to the NLSF codebook for the current signal type and LPC order */ + psNLSF_CB = psEnc->sCmn.psNLSF_CB[ psEncCtrl->sCmn.sigtype ]; + + /* Quantize NLSF parameters given the trained NLSF codebooks */ + TIC(MSVQ_encode_FIX) + SKP_Silk_NLSF_MSVQ_encode_FIX( psEncCtrl->sCmn.NLSFIndices, pNLSF_Q15, psNLSF_CB, + psEnc->sPred.prev_NLSFq_Q15, pNLSFW_Q6, NLSF_mu_Q15, NLSF_mu_fluc_red_Q16, + psEnc->sCmn.NLSF_MSVQ_Survivors, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.first_frame_after_reset ); + TOC(MSVQ_encode_FIX) + + /* Convert quantized NLSFs back to LPC coefficients */ + SKP_Silk_NLSF2A_stable( psEncCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psEnc->sCmn.predictLPCOrder ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + SKP_Silk_interpolate( pNLSF0_temp_Q15, psEnc->sPred.prev_NLSFq_Q15, pNLSF_Q15, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sCmn.predictLPCOrder ); + + /* Convert back to LPC coefficients */ + SKP_Silk_NLSF2A_stable( psEncCtrl->PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEnc->sCmn.predictLPCOrder ); + + } else { + /* Copy LPC coefficients for first half from second half */ + SKP_memcpy( psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->PredCoef_Q12[ 1 ], psEnc->sCmn.predictLPCOrder * sizeof( SKP_int16 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_process_gains_FIX.c b/pkg/silk/csilk/SKP_Silk_process_gains_FIX.c new file mode 100644 index 0000000..518152a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_process_gains_FIX.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Processing of gains */ +void SKP_Silk_process_gains_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state_FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O Encoder control_FIX */ +) +{ + SKP_Silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + SKP_int k; + SKP_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /*s = -0.5f * SKP_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SKP_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains_Q16[ k ] = SKP_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal_Q16 = SKP_DIV32_16( SKP_Silk_log2lin( + SKP_SMULWB( SKP_FIX_CONST( 70.0, 7 ) - psEncCtrl->current_SNR_dB_Q7, SKP_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < NB_SUBFR; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = SKP_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + if( psEncCtrl->ResNrgQ[ k ] < 32 ) { + ResNrgPart = SKP_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + ResNrgPart = 0; + } + } else if( psEncCtrl->ResNrgQ[k] != 0 ) { + if( ResNrgPart > SKP_RSHIFT( SKP_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = SKP_int32_MAX; + } else { + ResNrgPart = SKP_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = SKP_ADD_SAT32( ResNrgPart, SKP_SMMUL( gain, gain ) ); + if( gain_squared < SKP_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = SKP_SMLAWW( SKP_LSHIFT( ResNrgPart, 16 ), gain, gain ); + SKP_assert( gain_squared > 0 ); + gain = SKP_Silk_SQRT_APPROX( gain_squared ); /* Q8 */ + psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = SKP_Silk_SQRT_APPROX( gain_squared ); /* Q0 */ + psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Noise shaping quantization */ + SKP_Silk_gains_quant( psEncCtrl->sCmn.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, psEnc->sCmn.nFramesInPayloadBuf ); + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + SKP_RSHIFT( psEncCtrl->input_tilt_Q15, 8 ) > SKP_FIX_CONST( 1.0, 7 ) ) { + psEncCtrl->sCmn.QuantOffsetType = 0; + } else { + psEncCtrl->sCmn.QuantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrl->sCmn.sigtype ][ psEncCtrl->sCmn.QuantOffsetType ]; + psEncCtrl->Lambda_Q10 = SKP_FIX_CONST( LAMBDA_OFFSET, 10 ) + + SKP_SMULBB( SKP_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->speech_activity_Q8 ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + SKP_assert( psEncCtrl->Lambda_Q10 > 0 ); + SKP_assert( psEncCtrl->Lambda_Q10 < SKP_FIX_CONST( 2, 10 ) ); +} diff --git a/pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c b/pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c new file mode 100644 index 0000000..6caf0ff --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +void SKP_Silk_quant_LTP_gains_FIX( + SKP_int16 B_Q14[], /* I/O (un)quantized LTP gains */ + SKP_int cbk_index[], /* O Codebook Index */ + SKP_int *periodicity_index, /* O Periodicity Index */ + const SKP_int32 W_Q18[], /* I Error Weights in Q18 */ + SKP_int mu_Q8, /* I Mu value (R/D tradeoff) */ + SKP_int lowComplexity /* I Flag for low complexity */ +) +{ + SKP_int j, k, temp_idx[ NB_SUBFR ], cbk_size; + const SKP_int16 *cl_ptr; + const SKP_int16 *cbk_ptr_Q14; + const SKP_int16 *b_Q14_ptr; + const SKP_int32 *W_Q18_ptr; + SKP_int32 rate_dist_subfr, rate_dist, min_rate_dist; + + + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist = SKP_int32_MAX; + for( k = 0; k < 3; k++ ) { + cl_ptr = SKP_Silk_LTP_gain_BITS_Q6_ptrs[ k ]; + cbk_ptr_Q14 = SKP_Silk_LTP_vq_ptrs_Q14[ k ]; + cbk_size = SKP_Silk_LTP_vq_sizes[ k ]; + + /* Setup pointer to first subframe */ + W_Q18_ptr = W_Q18; + b_Q14_ptr = B_Q14; + + rate_dist = 0; + for( j = 0; j < NB_SUBFR; j++ ) { + + SKP_Silk_VQ_WMat_EC_FIX( + &temp_idx[ j ], /* O index of best codebook vector */ + &rate_dist_subfr, /* O best weighted quantization error + mu * rate */ + b_Q14_ptr, /* I input vector to be quantized */ + W_Q18_ptr, /* I weighting matrix */ + cbk_ptr_Q14, /* I codebook */ + cl_ptr, /* I code length for each codebook vector */ + mu_Q8, /* I tradeoff between weighted error and rate */ + cbk_size /* I number of vectors in codebook */ + ); + + rate_dist = SKP_ADD_POS_SAT32( rate_dist, rate_dist_subfr ); + + b_Q14_ptr += LTP_ORDER; + W_Q18_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Avoid never finding a codebook */ + rate_dist = SKP_min( SKP_int32_MAX - 1, rate_dist ); + + if( rate_dist < min_rate_dist ) { + min_rate_dist = rate_dist; + SKP_memcpy( cbk_index, temp_idx, NB_SUBFR * sizeof( SKP_int ) ); + *periodicity_index = k; + } + + /* Break early in low-complexity mode if rate distortion is below threshold */ + if( lowComplexity && ( rate_dist < SKP_Silk_LTP_gain_middle_avg_RD_Q14 ) ) { + break; + } + } + + cbk_ptr_Q14 = SKP_Silk_LTP_vq_ptrs_Q14[ *periodicity_index ]; + for( j = 0; j < NB_SUBFR; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = cbk_ptr_Q14[ SKP_MLA( k, cbk_index[ j ], LTP_ORDER ) ]; + } + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_range_coder.c b/pkg/silk/csilk/SKP_Silk_range_coder.c new file mode 100644 index 0000000..45f9ce4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_range_coder.c @@ -0,0 +1,372 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* Range encoder for one symbol */ +void SKP_Silk_range_encoder( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data, /* I uncompressed data */ + const SKP_uint16 prob[] /* I cumulative density functions */ +) +{ + SKP_uint32 low_Q16, high_Q16; + SKP_uint32 base_tmp, range_Q32; + + /* Copy structure data */ + SKP_uint32 base_Q32 = psRC->base_Q32; + SKP_uint32 range_Q16 = psRC->range_Q16; + SKP_int32 bufferIx = psRC->bufferIx; + SKP_uint8 *buffer = psRC->buffer; + + if( psRC->error ) { + return; + } + + /* Update interval */ + low_Q16 = prob[ data ]; + high_Q16 = prob[ data + 1 ]; + base_tmp = base_Q32; /* save current base, to test for carry */ + base_Q32 += SKP_MUL_uint( range_Q16, low_Q16 ); + range_Q32 = SKP_MUL_uint( range_Q16, high_Q16 - low_Q16 ); + + /* Check for carry */ + if( base_Q32 < base_tmp ) { + /* Propagate carry in buffer */ + SKP_int bufferIx_tmp = bufferIx; + while( ( ++buffer[ --bufferIx_tmp ] ) == 0 ); + } + + /* Check normalization */ + if( range_Q32 & 0xFF000000 ) { + /* No normalization */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 16 ); + } else { + if( range_Q32 & 0xFFFF0000 ) { + /* Normalization of 8 bits shift */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 8 ); + } else { + /* Normalization of 16 bits shift */ + range_Q16 = range_Q32; + /* Make sure not to write beyond buffer */ + if( bufferIx >= psRC->bufferLength ) { + psRC->error = RANGE_CODER_WRITE_BEYOND_BUFFER; + return; + } + /* Write one byte to buffer */ + buffer[ bufferIx++ ] = (SKP_uint8)( SKP_RSHIFT_uint( base_Q32, 24 ) ); + base_Q32 = SKP_LSHIFT_ovflw( base_Q32, 8 ); + } + /* Make sure not to write beyond buffer */ + if( bufferIx >= psRC->bufferLength ) { + psRC->error = RANGE_CODER_WRITE_BEYOND_BUFFER; + return; + } + /* Write one byte to buffer */ + buffer[ bufferIx++ ] = (SKP_uint8)( SKP_RSHIFT_uint( base_Q32, 24 ) ); + base_Q32 = SKP_LSHIFT_ovflw( base_Q32, 8 ); + } + + /* Copy structure data back */ + psRC->base_Q32 = base_Q32; + psRC->range_Q16 = range_Q16; + psRC->bufferIx = bufferIx; +} + +/* Range encoder for multiple symbols */ +void SKP_Silk_range_encoder_multi( + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_int data[], /* I uncompressed data [nSymbols] */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int nSymbols /* I number of data symbols */ +) +{ + SKP_int k; + for( k = 0; k < nSymbols; k++ ) { + SKP_Silk_range_encoder( psRC, data[ k ], prob[ k ] ); + } +} + +/* Range decoder for one symbol */ +void SKP_Silk_range_decoder( + SKP_int data[], /* O uncompressed data */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 prob[], /* I cumulative density function */ + SKP_int probIx /* I initial (middle) entry of cdf */ +) +{ + SKP_uint32 low_Q16, high_Q16; + SKP_uint32 base_tmp, range_Q32; + + /* Copy structure data */ + SKP_uint32 base_Q32 = psRC->base_Q32; + SKP_uint32 range_Q16 = psRC->range_Q16; + SKP_int32 bufferIx = psRC->bufferIx; + SKP_uint8 *buffer = &psRC->buffer[ 4 ]; + + if( psRC->error ) { + /* Set output to zero */ + *data = 0; + return; + } + + high_Q16 = prob[ probIx ]; + base_tmp = SKP_MUL_uint( range_Q16, high_Q16 ); + if( base_tmp > base_Q32 ) { + while( 1 ) { + low_Q16 = prob[ --probIx ]; + base_tmp = SKP_MUL_uint( range_Q16, low_Q16 ); + if( base_tmp <= base_Q32 ) { + break; + } + high_Q16 = low_Q16; + /* Test for out of range */ + if( high_Q16 == 0 ) { + psRC->error = RANGE_CODER_CDF_OUT_OF_RANGE; + /* Set output to zero */ + *data = 0; + return; + } + } + } else { + while( 1 ) { + low_Q16 = high_Q16; + high_Q16 = prob[ ++probIx ]; + base_tmp = SKP_MUL_uint( range_Q16, high_Q16 ); + if( base_tmp > base_Q32 ) { + probIx--; + break; + } + /* Test for out of range */ + if( high_Q16 == 0xFFFF ) { + psRC->error = RANGE_CODER_CDF_OUT_OF_RANGE; + /* Set output to zero */ + *data = 0; + return; + } + } + } + *data = probIx; + base_Q32 -= SKP_MUL_uint( range_Q16, low_Q16 ); + range_Q32 = SKP_MUL_uint( range_Q16, high_Q16 - low_Q16 ); + + /* Check normalization */ + if( range_Q32 & 0xFF000000 ) { + /* No normalization */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 16 ); + } else { + if( range_Q32 & 0xFFFF0000 ) { + /* Normalization of 8 bits shift */ + range_Q16 = SKP_RSHIFT_uint( range_Q32, 8 ); + /* Check for errors */ + if( SKP_RSHIFT_uint( base_Q32, 24 ) ) { + psRC->error = RANGE_CODER_NORMALIZATION_FAILED; + /* Set output to zero */ + *data = 0; + return; + } + } else { + /* Normalization of 16 bits shift */ + range_Q16 = range_Q32; + /* Check for errors */ + if( SKP_RSHIFT( base_Q32, 16 ) ) { + psRC->error = RANGE_CODER_NORMALIZATION_FAILED; + /* Set output to zero */ + *data = 0; + return; + } + /* Update base */ + base_Q32 = SKP_LSHIFT_uint( base_Q32, 8 ); + /* Make sure not to read beyond buffer */ + if( bufferIx < psRC->bufferLength ) { + /* Read one byte from buffer */ + base_Q32 |= (SKP_uint32)buffer[ bufferIx++ ]; + } + } + /* Update base */ + base_Q32 = SKP_LSHIFT_uint( base_Q32, 8 ); + /* Make sure not to read beyond buffer */ + if( bufferIx < psRC->bufferLength ) { + /* Read one byte from buffer */ + base_Q32 |= (SKP_uint32)buffer[ bufferIx++ ]; + } + } + + /* Check for zero interval length */ + if( range_Q16 == 0 ) { + psRC->error = RANGE_CODER_ZERO_INTERVAL_WIDTH; + /* Set output to zero */ + *data = 0; + return; + } + + /* Copy structure data back */ + psRC->base_Q32 = base_Q32; + psRC->range_Q16 = range_Q16; + psRC->bufferIx = bufferIx; +} + +/* Range decoder for multiple symbols */ +void SKP_Silk_range_decoder_multi( + SKP_int data[], /* O uncompressed data [nSymbols] */ + SKP_Silk_range_coder_state *psRC, /* I/O compressor data structure */ + const SKP_uint16 * const prob[], /* I cumulative density functions */ + const SKP_int probStartIx[], /* I initial (middle) entries of cdfs [nSymbols] */ + const SKP_int nSymbols /* I number of data symbols */ +) +{ + SKP_int k; + for( k = 0; k < nSymbols; k++ ) { + SKP_Silk_range_decoder( &data[ k ], psRC, prob[ k ], probStartIx[ k ] ); + } +} + +/* Initialize range encoder */ +void SKP_Silk_range_enc_init( + SKP_Silk_range_coder_state *psRC /* O compressor data structure */ +) +{ + /* Initialize structure */ + psRC->bufferLength = MAX_ARITHM_BYTES; + psRC->range_Q16 = 0x0000FFFF; + psRC->bufferIx = 0; + psRC->base_Q32 = 0; + psRC->error = 0; +} + +/* Initialize range decoder */ +void SKP_Silk_range_dec_init( + SKP_Silk_range_coder_state *psRC, /* O compressor data structure */ + const SKP_uint8 buffer[], /* I buffer for compressed data [bufferLength] */ + const SKP_int32 bufferLength /* I buffer length (in bytes) */ +) +{ + /* check input */ + if( ( bufferLength > MAX_ARITHM_BYTES ) || ( bufferLength < 0 ) ) { + psRC->error = RANGE_CODER_DEC_PAYLOAD_TOO_LONG; + return; + } + /* Initialize structure */ + /* Copy to internal buffer */ + SKP_memcpy( psRC->buffer, buffer, bufferLength * sizeof( SKP_uint8 ) ); + psRC->bufferLength = bufferLength; + psRC->bufferIx = 0; + psRC->base_Q32 = + SKP_LSHIFT_uint( (SKP_uint32)buffer[ 0 ], 24 ) | + SKP_LSHIFT_uint( (SKP_uint32)buffer[ 1 ], 16 ) | + SKP_LSHIFT_uint( (SKP_uint32)buffer[ 2 ], 8 ) | + (SKP_uint32)buffer[ 3 ]; + psRC->range_Q16 = 0x0000FFFF; + psRC->error = 0; +} + +/* Determine length of bitstream */ +SKP_int SKP_Silk_range_coder_get_length( /* O returns number of BITS in stream */ + const SKP_Silk_range_coder_state *psRC, /* I compressed data structure */ + SKP_int *nBytes /* O number of BYTES in stream */ +) +{ + SKP_int nBits; + + /* Number of bits in stream */ + nBits = SKP_LSHIFT( psRC->bufferIx, 3 ) + SKP_Silk_CLZ32( psRC->range_Q16 - 1 ) - 14; + + *nBytes = SKP_RSHIFT( nBits + 7, 3 ); + + /* Return number of bits in bitstream */ + return nBits; +} + +/* Write shortest uniquely decodable stream to buffer, and determine its length */ +void SKP_Silk_range_enc_wrap_up( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +) +{ + SKP_int bufferIx_tmp, bits_to_store, bits_in_stream, nBytes, mask; + SKP_uint32 base_Q24; + + /* Lower limit of interval, shifted 8 bits to the right */ + base_Q24 = SKP_RSHIFT_uint( psRC->base_Q32, 8 ); + + bits_in_stream = SKP_Silk_range_coder_get_length( psRC, &nBytes ); + + /* Number of additional bits (1..9) required to be stored to stream */ + bits_to_store = bits_in_stream - SKP_LSHIFT( psRC->bufferIx, 3 ); + /* Round up to required resolution */ + base_Q24 += SKP_RSHIFT_uint( 0x00800000, bits_to_store - 1 ); + base_Q24 &= SKP_LSHIFT_ovflw( 0xFFFFFFFF, 24 - bits_to_store ); + + /* Check for carry */ + if( base_Q24 & 0x01000000 ) { + /* Propagate carry in buffer */ + bufferIx_tmp = psRC->bufferIx; + while( ( ++( psRC->buffer[ --bufferIx_tmp ] ) ) == 0 ); + } + + /* Store to stream, making sure not to write beyond buffer */ + if( psRC->bufferIx < psRC->bufferLength ) { + psRC->buffer[ psRC->bufferIx++ ] = (SKP_uint8)SKP_RSHIFT_uint( base_Q24, 16 ); + if( bits_to_store > 8 ) { + if( psRC->bufferIx < psRC->bufferLength ) { + psRC->buffer[ psRC->bufferIx++ ] = (SKP_uint8)SKP_RSHIFT_uint( base_Q24, 8 ); + } + } + } + + /* Fill up any remaining bits in the last byte with 1s */ + if( bits_in_stream & 7 ) { + mask = SKP_RSHIFT( 0xFF, bits_in_stream & 7 ); + if( nBytes - 1 < psRC->bufferLength ) { + psRC->buffer[ nBytes - 1 ] |= mask; + } + } +} + +/* Check that any remaining bits in the last byte are set to 1 */ +void SKP_Silk_range_coder_check_after_decoding( + SKP_Silk_range_coder_state *psRC /* I/O compressed data structure */ +) +{ + SKP_int bits_in_stream, nBytes, mask; + + bits_in_stream = SKP_Silk_range_coder_get_length( psRC, &nBytes ); + + /* Make sure not to read beyond buffer */ + if( nBytes - 1 >= psRC->bufferLength ) { + psRC->error = RANGE_CODER_DECODER_CHECK_FAILED; + return; + } + + /* Test any remaining bits in last byte */ + if( bits_in_stream & 7 ) { + mask = SKP_RSHIFT( 0xFF, bits_in_stream & 7 ); + if( ( psRC->buffer[ nBytes - 1 ] & mask ) != mask ) { + psRC->error = RANGE_CODER_DECODER_CHECK_FAILED; + return; + } + } +} diff --git a/pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.c b/pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.c new file mode 100644 index 0000000..e2700ac --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.c @@ -0,0 +1,43 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Add noise to matrix diagonal */ +void SKP_Silk_regularize_correlations_FIX( + SKP_int32 *XX, /* I/O Correlation matrices */ + SKP_int32 *xx, /* I/O Correlation values */ + SKP_int32 noise, /* I Noise to add */ + SKP_int D /* I Dimension of XX */ +) +{ + SKP_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = SKP_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler.c b/pkg/silk/csilk/SKP_Silk_resampler.c new file mode 100644 index 0000000..c3d25e5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler.c @@ -0,0 +1,323 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler.c * + * * + * Description: Interface to collection of resamplers * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +/* Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 32 44.1 48 + * + * 8 C UF U UF UF UF UF + * 12 AF C UF U UF UF UF + * 16 D AF C UF U UF UF + * Fs_in (kHz) 24 AIF D AF C UF UF U + * 32 UF AF D AF C UF UF + * 44.1 AMI AMI AMI AMI AMI C UF + * 48 DAF DAF AF D AF UF C + * + * default method: UF + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * DAF -> Allpass-based 2x downsampling followed by AR2 filter followed by FIR interpolation + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AMI -> ARMA4 filter followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + * + * Input signals sampled above 48 kHz are first downsampled to at most 48 kHz. + * Output signals sampled above 48 kHz are upsampled from at most 48 kHz. + */ + +#include "SKP_Silk_resampler_private.h" + +/* Greatest common divisor */ +static SKP_int32 gcd( + SKP_int32 a, + SKP_int32 b +) +{ + SKP_int32 tmp; + while( b > 0 ) { + tmp = a - b * SKP_DIV32( a, b ); + a = b; + b = tmp; + } + return a; +} + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +SKP_int SKP_Silk_resampler_init( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int32 Fs_Hz_in, /* I: Input sampling rate (Hz) */ + SKP_int32 Fs_Hz_out /* I: Output sampling rate (Hz) */ +) +{ + SKP_int32 cycleLen, cyclesPerBatch, up2 = 0, down2 = 0; + + /* Clear state */ + SKP_memset( S, 0, sizeof( SKP_Silk_resampler_state_struct ) ); + + /* Input checking */ +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + if( Fs_Hz_in < 8000 || Fs_Hz_in > 192000 || Fs_Hz_out < 8000 || Fs_Hz_out > 192000 ) { +#else + if( Fs_Hz_in < 8000 || Fs_Hz_in > 48000 || Fs_Hz_out < 8000 || Fs_Hz_out > 48000 ) { +#endif + SKP_assert( 0 ); + return -1; + } + +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + /* Determine pre downsampling and post upsampling */ + if( Fs_Hz_in > 96000 ) { + S->nPreDownsamplers = 2; + S->down_pre_function = SKP_Silk_resampler_private_down4; + } else if( Fs_Hz_in > 48000 ) { + S->nPreDownsamplers = 1; + S->down_pre_function = SKP_Silk_resampler_down2; + } else { + S->nPreDownsamplers = 0; + S->down_pre_function = NULL; + } + + if( Fs_Hz_out > 96000 ) { + S->nPostUpsamplers = 2; + S->up_post_function = SKP_Silk_resampler_private_up4; + } else if( Fs_Hz_out > 48000 ) { + S->nPostUpsamplers = 1; + S->up_post_function = SKP_Silk_resampler_up2; + } else { + S->nPostUpsamplers = 0; + S->up_post_function = NULL; + } + + if( S->nPreDownsamplers + S->nPostUpsamplers > 0 ) { + /* Ratio of output/input samples */ + S->ratio_Q16 = SKP_LSHIFT32( SKP_DIV32( SKP_LSHIFT32( Fs_Hz_out, 13 ), Fs_Hz_in ), 3 ); + /* Make sure the ratio is rounded up */ + while( SKP_SMULWW( S->ratio_Q16, Fs_Hz_in ) < Fs_Hz_out ) S->ratio_Q16++; + + /* Batch size is 10 ms */ + S->batchSizePrePost = SKP_DIV32_16( Fs_Hz_in, 100 ); + + /* Convert sampling rate to those after pre-downsampling and before post-upsampling */ + Fs_Hz_in = SKP_RSHIFT( Fs_Hz_in, S->nPreDownsamplers ); + Fs_Hz_out = SKP_RSHIFT( Fs_Hz_out, S->nPostUpsamplers ); + } +#endif + + /* Number of samples processed per batch */ + /* First, try 10 ms frames */ + S->batchSize = SKP_DIV32_16( Fs_Hz_in, 100 ); + if( ( SKP_MUL( S->batchSize, 100 ) != Fs_Hz_in ) || ( Fs_Hz_in % 100 != 0 ) ) { + /* No integer number of input or output samples with 10 ms frames, use greatest common divisor */ + cycleLen = SKP_DIV32( Fs_Hz_in, gcd( Fs_Hz_in, Fs_Hz_out ) ); + cyclesPerBatch = SKP_DIV32( RESAMPLER_MAX_BATCH_SIZE_IN, cycleLen ); + if( cyclesPerBatch == 0 ) { + /* cycleLen too big, let's just use the maximum batch size. Some distortion will result. */ + S->batchSize = RESAMPLER_MAX_BATCH_SIZE_IN; + SKP_assert( 0 ); + } else { + S->batchSize = SKP_MUL( cyclesPerBatch, cycleLen ); + } + } + + + /* Find resampler with the right sampling ratio */ + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == SKP_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = SKP_Silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + up2 = 1; + if( Fs_Hz_in > 24000 ) { + /* Low-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_up2; + } else { + /* High-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_private_up2_HQ; + } + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + if( SKP_MUL( Fs_Hz_out, 4 ) == SKP_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->Coefs = SKP_Silk_Resampler_3_4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 3 ) == SKP_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->Coefs = SKP_Silk_Resampler_2_3_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->Coefs = SKP_Silk_Resampler_1_2_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 8 ) == SKP_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 8 */ + S->FIR_Fracs = 3; + S->Coefs = SKP_Silk_Resampler_3_8_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->Coefs = SKP_Silk_Resampler_1_3_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + down2 = 1; + S->Coefs = SKP_Silk_Resampler_1_2_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + down2 = 1; + S->Coefs = SKP_Silk_Resampler_1_3_COEFS; + S->resampler_function = SKP_Silk_resampler_private_down_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 80 ) ) { /* Fs_out : Fs_in = 80 : 441 */ + S->Coefs = SKP_Silk_Resampler_80_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 120 ) ) { /* Fs_out : Fs_in = 120 : 441 */ + S->Coefs = SKP_Silk_Resampler_120_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 160 ) ) { /* Fs_out : Fs_in = 160 : 441 */ + S->Coefs = SKP_Silk_Resampler_160_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 240 ) ) { /* Fs_out : Fs_in = 240 : 441 */ + S->Coefs = SKP_Silk_Resampler_240_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else if( SKP_MUL( Fs_Hz_out, 441 ) == SKP_MUL( Fs_Hz_in, 320 ) ) { /* Fs_out : Fs_in = 320 : 441 */ + S->Coefs = SKP_Silk_Resampler_320_441_ARMA4_COEFS; + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + } else { + /* Default resampler */ + S->resampler_function = SKP_Silk_resampler_private_IIR_FIR; + up2 = 1; + if( Fs_Hz_in > 24000 ) { + /* Low-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_up2; + } else { + /* High-quality all-pass upsampler */ + S->up2_function = SKP_Silk_resampler_private_up2_HQ; + } + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = SKP_Silk_resampler_private_copy; + } + + S->input2x = up2 | down2; + + /* Ratio of input/output samples */ + S->invRatio_Q16 = SKP_LSHIFT32( SKP_DIV32( SKP_LSHIFT32( Fs_Hz_in, 14 + up2 - down2 ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( SKP_SMULWW( S->invRatio_Q16, SKP_LSHIFT32( Fs_Hz_out, down2 ) ) < SKP_LSHIFT32( Fs_Hz_in, up2 ) ) { + S->invRatio_Q16++; + } + + S->magic_number = 123456789; + + return 0; +} + +/* Clear the states of all resampling filters, without resetting sampling rate ratio */ +SKP_int SKP_Silk_resampler_clear( + SKP_Silk_resampler_state_struct *S /* I/O: Resampler state */ +) +{ + /* Clear state */ + SKP_memset( S->sDown2, 0, sizeof( S->sDown2 ) ); + SKP_memset( S->sIIR, 0, sizeof( S->sIIR ) ); + SKP_memset( S->sFIR, 0, sizeof( S->sFIR ) ); +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + SKP_memset( S->sDownPre, 0, sizeof( S->sDownPre ) ); + SKP_memset( S->sUpPost, 0, sizeof( S->sUpPost ) ); +#endif + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +SKP_int SKP_Silk_resampler( + SKP_Silk_resampler_state_struct *S, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + /* Verify that state was initialized and has not been corrupted */ + if( S->magic_number != 123456789 ) { + SKP_assert( 0 ); + return -1; + } + +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + if( S->nPreDownsamplers + S->nPostUpsamplers > 0 ) { + /* The input and/or output sampling rate is above 48000 Hz */ + SKP_int32 nSamplesIn, nSamplesOut; + SKP_int16 in_buf[ 480 ], out_buf[ 480 ]; + + while( inLen > 0 ) { + /* Number of input and output samples to process */ + nSamplesIn = SKP_min( inLen, S->batchSizePrePost ); + nSamplesOut = SKP_SMULWB( S->ratio_Q16, nSamplesIn ); + + SKP_assert( SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) <= 480 ); + SKP_assert( SKP_RSHIFT32( nSamplesOut, S->nPostUpsamplers ) <= 480 ); + + if( S->nPreDownsamplers > 0 ) { + S->down_pre_function( S->sDownPre, in_buf, in, nSamplesIn ); + if( S->nPostUpsamplers > 0 ) { + S->resampler_function( S, out_buf, in_buf, SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) ); + S->up_post_function( S->sUpPost, out, out_buf, SKP_RSHIFT32( nSamplesOut, S->nPostUpsamplers ) ); + } else { + S->resampler_function( S, out, in_buf, SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) ); + } + } else { + S->resampler_function( S, out_buf, in, SKP_RSHIFT32( nSamplesIn, S->nPreDownsamplers ) ); + S->up_post_function( S->sUpPost, out, out_buf, SKP_RSHIFT32( nSamplesOut, S->nPostUpsamplers ) ); + } + + in += nSamplesIn; + out += nSamplesOut; + inLen -= nSamplesIn; + } + } else +#endif + { + /* Input and output sampling rate are at most 48000 Hz */ + S->resampler_function( S, out, in, inLen ); + } + + return 0; +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_down2.c b/pkg/silk/csilk/SKP_Silk_resampler_down2.c new file mode 100644 index 0000000..fedba1f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_down2.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_down2.c * + * * + * Downsample by a factor 2, mediocre quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_rom.h" + +#if (EMBEDDED_ARM<5) +/* Downsample by a factor 2, mediocre quality */ +void SKP_Silk_resampler_down2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ len ] */ + const SKP_int16 *in, /* I: Input signal [ floor(len/2) ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 k, len2 = SKP_RSHIFT32( inLen, 1 ); + SKP_int32 in32, out32, Y, X; + + SKP_assert( SKP_Silk_resampler_down2_0 > 0 ); + SKP_assert( SKP_Silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_down2_1 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_down2_0 ); + out32 = SKP_ADD32( out32, S[ 1 ] ); + out32 = SKP_ADD32( out32, X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 11 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_resampler_down2_3.c b/pkg/silk/csilk/SKP_Silk_resampler_down2_3.c new file mode 100644 index 0000000..59ecc7c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_down2_3.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_down2_3.c * + * * + * Downsample by a factor 2/3, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +#undef ORDER_FIR +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void SKP_Silk_resampler_down2_3( + SKP_int32 *S, /* I/O: State vector [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ floor(2*inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 nSamplesIn, counter, res_Q6; + SKP_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR ]; + SKP_int32 *buf_ptr; + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf, S, ORDER_FIR * sizeof( SKP_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = SKP_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + SKP_Silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = SKP_SMULWB( buf_ptr[ 0 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 1 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = SKP_SMULWB( buf_ptr[ 1 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 4 ], SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_down3.c b/pkg/silk/csilk/SKP_Silk_resampler_down3.c new file mode 100644 index 0000000..2cc601e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_down3.c @@ -0,0 +1,94 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_down3.c * + * * + * Downsample by a factor 3, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +#undef ORDER_FIR +#define ORDER_FIR 6 + +/* Downsample by a factor 3, low quality */ +void SKP_Silk_resampler_down3( + SKP_int32 *S, /* I/O: State vector [ 8 ] */ + SKP_int16 *out, /* O: Output signal [ floor(inLen/3) ] */ + const SKP_int16 *in, /* I: Input signal [ inLen ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 nSamplesIn, counter, res_Q6; + SKP_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR ]; + SKP_int32 *buf_ptr; + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf, S, ORDER_FIR * sizeof( SKP_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = SKP_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + SKP_Silk_Resampler_1_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = SKP_SMULWB( SKP_ADD32( buf_ptr[ 0 ], buf_ptr[ 5 ] ), SKP_Silk_Resampler_1_3_COEFS_LQ[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 1 ], buf_ptr[ 4 ] ), SKP_Silk_Resampler_1_3_COEFS_LQ[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 2 ], buf_ptr[ 3 ] ), SKP_Silk_Resampler_1_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( SKP_int32 ) ); +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private.h b/pkg/silk/csilk/SKP_Silk_resampler_private.h new file mode 100644 index 0000000..04563fa --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private.h @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_structs.h * + * * + * Description: Structs for IIR/FIR resamplers * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * * + * */ + +#ifndef SKP_Silk_RESAMPLER_H +#define SKP_Silk_RESAMPLER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_structs.h" +#include "SKP_Silk_resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_IN 480 + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void SKP_Silk_resampler_private_IIR_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void SKP_Silk_resampler_private_down_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Copy */ +void SKP_Silk_resampler_private_copy( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void SKP_Silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void SKP_Silk_resampler_private_up2_HQ( + SKP_int32 *S, /* I/O: Resampler state [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/* Upsample 4x, low quality */ +void SKP_Silk_resampler_private_up4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 4 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +); + +/* Downsample 4x, low quality */ +void SKP_Silk_resampler_private_down4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ floor(len/2) ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 inLen /* I: Number of input samples */ +); + +/* Second order AR filter */ +void SKP_Silk_resampler_private_AR2( + SKP_int32 S[], /* I/O: State vector [ 2 ] */ + SKP_int32 out_Q8[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 A_Q14[], /* I: AR coefficients, Q14 */ + SKP_int32 len /* I: Signal length */ +); + +/* Fourth order ARMA filter */ +void SKP_Silk_resampler_private_ARMA4( + SKP_int32 S[], /* I/O: State vector [ 4 ] */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 Coef[], /* I: ARMA coefficients [ 7 ] */ + SKP_int32 len /* I: Signal length */ +); + + +#ifdef __cplusplus +} +#endif +#endif // SKP_Silk_RESAMPLER_H + diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c b/pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c new file mode 100644 index 0000000..5d581a4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_AR2. c * + * * + * Second order AR filter with single delay elements * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +#if (EMBEDDED_ARM<5) +/* Second order AR filter with single delay elements */ +void SKP_Silk_resampler_private_AR2( + SKP_int32 S[], /* I/O: State vector [ 2 ] */ + SKP_int32 out_Q8[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 A_Q14[], /* I: AR coefficients, Q14 */ + SKP_int32 len /* I: Signal length */ +) +{ + SKP_int32 k; + SKP_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = SKP_ADD_LSHIFT32( S[ 0 ], (SKP_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = SKP_LSHIFT( out32, 2 ); + S[ 0 ] = SKP_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = SKP_SMULWB( out32, A_Q14[ 1 ] ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c b/pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c new file mode 100644 index 0000000..4351592 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_ARMA4.c * + * * + * Fourth order ARMA filter, applies 64x gain * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Fourth order ARMA filter */ +/* Internally operates as two biquad filters in sequence. */ + +/* Coeffients are stored in a packed format: */ +/* { B1_Q14[1], B2_Q14[1], -A1_Q14[1], -A1_Q14[2], -A2_Q14[1], -A2_Q14[2], gain_Q16 } */ +/* where it is assumed that B*_Q14[0], B*_Q14[2], A*_Q14[0] are all 16384 */ +#if (EMBEDDED_ARM<5) +void SKP_Silk_resampler_private_ARMA4( + SKP_int32 S[], /* I/O: State vector [ 4 ] */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + const SKP_int16 Coef[], /* I: ARMA coefficients [ 7 ] */ + SKP_int32 len /* I: Signal length */ +) +{ + SKP_int32 k; + SKP_int32 in_Q8, out1_Q8, out2_Q8, X; + + for( k = 0; k < len; k++ ) { + in_Q8 = SKP_LSHIFT32( (SKP_int32)in[ k ], 8 ); + + /* Outputs of first and second biquad */ + out1_Q8 = SKP_ADD_LSHIFT32( in_Q8, S[ 0 ], 2 ); + out2_Q8 = SKP_ADD_LSHIFT32( out1_Q8, S[ 2 ], 2 ); + + /* Update states, which are stored in Q6. Coefficients are in Q14 here */ + X = SKP_SMLAWB( S[ 1 ], in_Q8, Coef[ 0 ] ); + S[ 0 ] = SKP_SMLAWB( X, out1_Q8, Coef[ 2 ] ); + + X = SKP_SMLAWB( S[ 3 ], out1_Q8, Coef[ 1 ] ); + S[ 2 ] = SKP_SMLAWB( X, out2_Q8, Coef[ 4 ] ); + + S[ 1 ] = SKP_SMLAWB( SKP_RSHIFT32( in_Q8, 2 ), out1_Q8, Coef[ 3 ] ); + S[ 3 ] = SKP_SMLAWB( SKP_RSHIFT32( out1_Q8, 2 ), out2_Q8, Coef[ 5 ] ); + + /* Apply gain and store to output. The coefficient is in Q16 */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( SKP_SMLAWB( 128, out2_Q8, Coef[ 6 ] ), 8 ) ); + } +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.c b/pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.c new file mode 100644 index 0000000..0976451 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.c @@ -0,0 +1,110 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_private_IIR_FIR.c * + * * + * Description: Hybrid IIR/FIR polyphase implementation of resampling * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" +#if EMBEDDED_ARM<5 +SKP_INLINE SKP_int16 *SKP_Silk_resampler_private_IIR_FIR_INTERPOL( + SKP_int16 * out, SKP_int16 * buf, SKP_int32 max_index_Q16 , SKP_int32 index_increment_Q16 ){ + SKP_int32 index_Q16, res_Q15; + SKP_int16 *buf_ptr; + SKP_int32 table_index; + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = SKP_SMULWB( index_Q16 & 0xFFFF, 144 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = SKP_SMULBB( buf_ptr[ 0 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 0 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 1 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 1 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 2 ], SKP_Silk_resampler_frac_FIR_144[ table_index ][ 2 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 3 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 2 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 4 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 1 ] ); + res_Q15 = SKP_SMLABB( res_Q15, buf_ptr[ 5 ], SKP_Silk_resampler_frac_FIR_144[ 143 - table_index ][ 0 ] ); + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +#else +extern SKP_int16 *SKP_Silk_resampler_private_IIR_FIR_INTERPOL( + SKP_int16 * out, SKP_int16 * buf, SKP_int32 max_index_Q16 , SKP_int32 index_increment_Q16 ); +#endif +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void SKP_Silk_resampler_private_IIR_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; + SKP_int32 nSamplesIn; + SKP_int32 max_index_Q16, index_increment_Q16; + SKP_int16 buf[ 2 * RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_144 ]; + + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = SKP_min( inLen, S->batchSize ); + + if( S->input2x == 1 ) { + /* Upsample 2x */ + S->up2_function( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, nSamplesIn ); + } else { + /* Fourth-order ARMA filter */ + SKP_Silk_resampler_private_ARMA4( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_144 ], in, S->Coefs, nSamplesIn ); + } + + max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 + S->input2x ); /* +1 if 2x upsampling */ + out = SKP_Silk_resampler_private_IIR_FIR_INTERPOL(out, buf, max_index_Q16, index_increment_Q16); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf, &buf[ nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S->sFIR, &buf[nSamplesIn << S->input2x ], RESAMPLER_ORDER_FIR_144 * sizeof( SKP_int32 ) ); +} + diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_copy.c b/pkg/silk/csilk/SKP_Silk_resampler_private_copy.c new file mode 100644 index 0000000..71df033 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_copy.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_private_copy.c * + * * + * Description: Copy. * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Copy */ +void SKP_Silk_resampler_private_copy( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_memcpy( out, in, inLen * sizeof( SKP_int16 ) ); +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_down4.c b/pkg/silk/csilk/SKP_Silk_resampler_private_down4.c new file mode 100644 index 0000000..3d65ad7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_down4.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_down4.c * + * * + * Downsample by a factor 4 * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Downsample by a factor 4. Note: very low quality, only use with input sampling rates above 96 kHz. */ +void SKP_Silk_resampler_private_down4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ floor(len/2) ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_int32 k, len4 = SKP_RSHIFT32( inLen, 2 ); + SKP_int32 in32, out32, Y, X; + + SKP_assert( SKP_Silk_resampler_down2_0 > 0 ); + SKP_assert( SKP_Silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len4; k++ ) { + /* Add two input samples and convert to Q10 */ + in32 = SKP_LSHIFT( SKP_ADD32( (SKP_int32)in[ 4 * k ], (SKP_int32)in[ 4 * k + 1 ] ), 9 ); + + /* All-pass section for even input sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_down2_1 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Add two input samples and convert to Q10 */ + in32 = SKP_LSHIFT( SKP_ADD32( (SKP_int32)in[ 4 * k + 2 ], (SKP_int32)in[ 4 * k + 3 ] ), 9 ); + + /* All-pass section for odd input sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_down2_0 ); + out32 = SKP_ADD32( out32, S[ 1 ] ); + out32 = SKP_ADD32( out32, X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 11 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c b/pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c new file mode 100644 index 0000000..4a441b1 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c @@ -0,0 +1,167 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_private_down_FIR.c * + * * + * Description: Hybrid IIR/FIR polyphase implementation of resampling * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" +#if EMBEDDED_ARM<5 +SKP_INLINE SKP_int16 *SKP_Silk_resampler_private_down_FIR_INTERPOL0( + SKP_int16 *out, SKP_int32 *buf2, const SKP_int16 *FIR_Coefs, SKP_int32 max_index_Q16, SKP_int32 index_increment_Q16){ + + SKP_int32 index_Q16, res_Q6; + SKP_int32 *buf_ptr; + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf2 + SKP_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = SKP_SMULWB( SKP_ADD32( buf_ptr[ 0 ], buf_ptr[ 11 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 1 ], buf_ptr[ 10 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 2 ], buf_ptr[ 9 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 3 ], buf_ptr[ 8 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 4 ], buf_ptr[ 7 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, SKP_ADD32( buf_ptr[ 5 ], buf_ptr[ 6 ] ), FIR_Coefs[ 5 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + } + return out; +} + +SKP_INLINE SKP_int16 *SKP_Silk_resampler_private_down_FIR_INTERPOL1( + SKP_int16 *out, SKP_int32 *buf2, const SKP_int16 *FIR_Coefs, SKP_int32 max_index_Q16, SKP_int32 index_increment_Q16, SKP_int32 FIR_Fracs){ + + SKP_int32 index_Q16, res_Q6; + SKP_int32 *buf_ptr; + SKP_int32 interpol_ind; + const SKP_int16 *interpol_ptr; + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf2 + SKP_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = SKP_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR / 2 * interpol_ind ]; + res_Q6 = SKP_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 0 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 1 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 2 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 3 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 4 ] ); + res_Q6 = SKP_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 5 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( res_Q6, 6 ) ); + } + return out; +} + +#else +extern SKP_int16 *SKP_Silk_resampler_private_down_FIR_INTERPOL0( + SKP_int16 *out, SKP_int32 *buf2, const SKP_int16 *FIR_Coefs, SKP_int32 max_index_Q16, SKP_int32 index_increment_Q16); +extern SKP_int16 *SKP_Silk_resampler_private_down_FIR_INTERPOL1( + SKP_int16 *out, SKP_int32 *buf2, const SKP_int16 *FIR_Coefs, SKP_int32 max_index_Q16, SKP_int32 index_increment_Q16, SKP_int32 FIR_Fracs); +#endif + +/* Resample with a 2x downsampler (optional), a 2nd order AR filter followed by FIR interpolation */ +void SKP_Silk_resampler_private_down_FIR( + void *SS, /* I/O: Resampler state */ + SKP_int16 out[], /* O: Output signal */ + const SKP_int16 in[], /* I: Input signal */ + SKP_int32 inLen /* I: Number of input samples */ +) +{ + SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; + SKP_int32 nSamplesIn; + SKP_int32 max_index_Q16, index_increment_Q16; + SKP_int16 buf1[ RESAMPLER_MAX_BATCH_SIZE_IN / 2 ]; + SKP_int32 buf2[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_DOWN_ORDER_FIR ]; + const SKP_int16 *FIR_Coefs; + + /* Copy buffered samples to start of buffer */ + SKP_memcpy( buf2, S->sFIR, RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = SKP_min( inLen, S->batchSize ); + + if( S->input2x == 1 ) { + /* Downsample 2x */ + SKP_Silk_resampler_down2( S->sDown2, buf1, in, nSamplesIn ); + + nSamplesIn = SKP_RSHIFT32( nSamplesIn, 1 ); + + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], buf1, S->Coefs, nSamplesIn ); + } else { + /* Second-order AR filter (output in Q8) */ + SKP_Silk_resampler_private_AR2( S->sIIR, &buf2[ RESAMPLER_DOWN_ORDER_FIR ], in, S->Coefs, nSamplesIn ); + } + + max_index_Q16 = SKP_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + if( S->FIR_Fracs == 1 ) { + out = SKP_Silk_resampler_private_down_FIR_INTERPOL0(out, buf2, FIR_Coefs, max_index_Q16, index_increment_Q16); + } else { + out = SKP_Silk_resampler_private_down_FIR_INTERPOL1(out, buf2, FIR_Coefs, max_index_Q16, index_increment_Q16, S->FIR_Fracs); + } + + in += nSamplesIn << S->input2x; + inLen -= nSamplesIn << S->input2x; + + if( inLen > S->input2x ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + SKP_memcpy( buf2, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + SKP_memcpy( S->sFIR, &buf2[ nSamplesIn ], RESAMPLER_DOWN_ORDER_FIR * sizeof( SKP_int32 ) ); +} + diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c b/pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c new file mode 100644 index 0000000..a95082e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c @@ -0,0 +1,120 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_up2_HQ.c * + * * + * Upsample by a factor 2, high quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +#if (EMBEDDED_ARM<5) +void SKP_Silk_resampler_private_up2_HQ( + SKP_int32 *S, /* I/O: Resampler state [ 6 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of INPUT samples */ +) +{ + SKP_int32 k; + SKP_int32 in32, out32_1, out32_2, Y, X; + + SKP_assert( SKP_Silk_resampler_up2_hq_0[ 0 ] > 0 ); + SKP_assert( SKP_Silk_resampler_up2_hq_0[ 1 ] < 0 ); + SKP_assert( SKP_Silk_resampler_up2_hq_1[ 0 ] > 0 ); + SKP_assert( SKP_Silk_resampler_up2_hq_1[ 1 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = SKP_SUB32( out32_1, S[ 1 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( out32_1, X ); + + /* Biquad notch filter */ + out32_2 = SKP_SMLAWB( out32_2, S[ 5 ], SKP_Silk_resampler_up2_hq_notch[ 2 ] ); + out32_2 = SKP_SMLAWB( out32_2, S[ 4 ], SKP_Silk_resampler_up2_hq_notch[ 1 ] ); + out32_1 = SKP_SMLAWB( out32_2, S[ 4 ], SKP_Silk_resampler_up2_hq_notch[ 0 ] ); + S[ 5 ] = SKP_SUB32( out32_2, S[ 5 ] ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( + SKP_SMLAWB( 256, out32_1, SKP_Silk_resampler_up2_hq_notch[ 3 ] ), 9 ) ); + + /* First all-pass section for odd output sample */ + Y = SKP_SUB32( in32, S[ 2 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = SKP_ADD32( S[ 2 ], X ); + S[ 2 ] = SKP_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = SKP_SUB32( out32_1, S[ 3 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = SKP_ADD32( S[ 3 ], X ); + S[ 3 ] = SKP_ADD32( out32_1, X ); + + /* Biquad notch filter */ + out32_2 = SKP_SMLAWB( out32_2, S[ 4 ], SKP_Silk_resampler_up2_hq_notch[ 2 ] ); + out32_2 = SKP_SMLAWB( out32_2, S[ 5 ], SKP_Silk_resampler_up2_hq_notch[ 1 ] ); + out32_1 = SKP_SMLAWB( out32_2, S[ 5 ], SKP_Silk_resampler_up2_hq_notch[ 0 ] ); + S[ 4 ] = SKP_SUB32( out32_2, S[ 4 ] ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT32( + SKP_SMLAWB( 256, out32_1, SKP_Silk_resampler_up2_hq_notch[ 3 ] ), 9 ) ); + } +} +#endif + + +void SKP_Silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O: Resampler state (unused) */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +) +{ + SKP_Silk_resampler_state_struct *S = (SKP_Silk_resampler_state_struct *)SS; + SKP_Silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_up4.c b/pkg/silk/csilk/SKP_Silk_resampler_private_up4.c new file mode 100644 index 0000000..f1cff61 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_up4.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_private_up4.c * + * * + * Upsample by a factor 4, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_private.h" + +/* Upsample by a factor 4, Note: very low quality, only use with output sampling rates above 96 kHz. */ +void SKP_Silk_resampler_private_up4( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 4 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of INPUT samples */ +) +{ + SKP_int32 k; + SKP_int32 in32, out32, Y, X; + SKP_int16 out16; + + SKP_assert( SKP_Silk_resampler_up2_lq_0 > 0 ); + SKP_assert( SKP_Silk_resampler_up2_lq_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ k ], 10 ); + + /* All-pass section for even output sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_lq_0 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out16 = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + out[ 4 * k ] = out16; + out[ 4 * k + 1 ] = out16; + + /* All-pass section for odd output sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_lq_1 ); + out32 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out16 = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + out[ 4 * k + 2 ] = out16; + out[ 4 * k + 3 ] = out16; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler_rom.c b/pkg/silk/csilk/SKP_Silk_resampler_rom.c new file mode 100644 index 0000000..b8e8ef8 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_rom.c @@ -0,0 +1,269 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_rom.c * + * * + * Description: Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 550 Words (1.1 kB) * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * */ + +#include "SKP_Silk_resampler_private.h" + +/* Tables for 2x downsampler */ +const SKP_int16 SKP_Silk_resampler_down2_0 = 9872; +const SKP_int16 SKP_Silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, low quality */ +const SKP_int16 SKP_Silk_resampler_up2_lq_0 = 8102; +const SKP_int16 SKP_Silk_resampler_up2_lq_1 = 36783 - 65536; + +/* Tables for 2x upsampler, high quality */ +const SKP_int16 SKP_Silk_resampler_up2_hq_0[ 2 ] = { 4280, 33727 - 65536 }; +const SKP_int16 SKP_Silk_resampler_up2_hq_1[ 2 ] = { 16295, 54015 - 65536 }; +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.12, 1]; A = [1, 0.055, 0.8]; G = 0.87; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]); */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +const SKP_int16 SKP_Silk_resampler_up2_hq_notch[ 4 ] = { 7864, -3604, 13107, 28508 }; + + +/* Tables with IIR and FIR coefficients for fractional downsamplers (70 Words) */ +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + -18249, -12532, + -97, 284, -495, 309, 10268, 20317, + -94, 156, -48, -720, 5984, 18278, + -45, -4, 237, -847, 2540, 14662, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + -11891, -12486, + 20, 211, -657, 688, 8423, 15911, + -44, 197, -152, -653, 3855, 13015, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + 2415, -13101, + 158, -295, -400, 1265, 4832, 7968, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_3_8_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + 13270, -13738, + -294, -123, 747, 2043, 3339, 3995, + -151, -311, 414, 1583, 2947, 3877, + -33, -389, 143, 1141, 2503, 3653, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ] = { + 16643, -14000, + -331, 19, 581, 1421, 2290, 2845, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_1_3_COEFS_LQ[ 2 + 3 ] = { + 16777, -9792, + 890, 1614, 2148, +}; + + +/* Tables with coefficients for 4th order ARMA filter (35 Words), in a packed format: */ +/* { B1_Q14[1], B2_Q14[1], -A1_Q14[1], -A1_Q14[2], -A2_Q14[1], -A2_Q14[2], gain_Q16 } */ +/* where it is assumed that B*_Q14[0], B*_Q14[2], A*_Q14[0] are all 16384 */ +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_320_441_ARMA4_COEFS[ 7 ] = { + 31454, 24746, -9706, -3386, -17911, -13243, 24797 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_240_441_ARMA4_COEFS[ 7 ] = { + 28721, 11254, 3189, -2546, -1495, -12618, 11562 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_160_441_ARMA4_COEFS[ 7 ] = { + 23492, -6457, 14358, -4856, 14654, -13008, 4456 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_120_441_ARMA4_COEFS[ 7 ] = { + 19311, -15569, 19489, -6950, 21441, -13559, 2370 +}; + +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_Resampler_80_441_ARMA4_COEFS[ 7 ] = { + 13248, -23849, 24126, -9486, 26806, -14286, 1065 +}; + +/* Table with interplation fractions of 1/288 : 2/288 : 287/288 (432 Words) */ +SKP_DWORD_ALIGN const SKP_int16 SKP_Silk_resampler_frac_FIR_144[ 144 ][ RESAMPLER_ORDER_FIR_144 / 2 ] = { + { -647, 1884, 30078}, + { -625, 1736, 30044}, + { -603, 1591, 30005}, + { -581, 1448, 29963}, + { -559, 1308, 29917}, + { -537, 1169, 29867}, + { -515, 1032, 29813}, + { -494, 898, 29755}, + { -473, 766, 29693}, + { -452, 636, 29627}, + { -431, 508, 29558}, + { -410, 383, 29484}, + { -390, 260, 29407}, + { -369, 139, 29327}, + { -349, 20, 29242}, + { -330, -97, 29154}, + { -310, -211, 29062}, + { -291, -324, 28967}, + { -271, -434, 28868}, + { -253, -542, 28765}, + { -234, -647, 28659}, + { -215, -751, 28550}, + { -197, -852, 28436}, + { -179, -951, 28320}, + { -162, -1048, 28200}, + { -144, -1143, 28077}, + { -127, -1235, 27950}, + { -110, -1326, 27820}, + { -94, -1414, 27687}, + { -77, -1500, 27550}, + { -61, -1584, 27410}, + { -45, -1665, 27268}, + { -30, -1745, 27122}, + { -15, -1822, 26972}, + { 0, -1897, 26820}, + { 15, -1970, 26665}, + { 29, -2041, 26507}, + { 44, -2110, 26346}, + { 57, -2177, 26182}, + { 71, -2242, 26015}, + { 84, -2305, 25845}, + { 97, -2365, 25673}, + { 110, -2424, 25498}, + { 122, -2480, 25320}, + { 134, -2534, 25140}, + { 146, -2587, 24956}, + { 157, -2637, 24771}, + { 168, -2685, 24583}, + { 179, -2732, 24392}, + { 190, -2776, 24199}, + { 200, -2819, 24003}, + { 210, -2859, 23805}, + { 220, -2898, 23605}, + { 229, -2934, 23403}, + { 238, -2969, 23198}, + { 247, -3002, 22992}, + { 255, -3033, 22783}, + { 263, -3062, 22572}, + { 271, -3089, 22359}, + { 279, -3114, 22144}, + { 286, -3138, 21927}, + { 293, -3160, 21709}, + { 300, -3180, 21488}, + { 306, -3198, 21266}, + { 312, -3215, 21042}, + { 318, -3229, 20816}, + { 323, -3242, 20589}, + { 328, -3254, 20360}, + { 333, -3263, 20130}, + { 338, -3272, 19898}, + { 342, -3278, 19665}, + { 346, -3283, 19430}, + { 350, -3286, 19194}, + { 353, -3288, 18957}, + { 356, -3288, 18718}, + { 359, -3286, 18478}, + { 362, -3283, 18238}, + { 364, -3279, 17996}, + { 366, -3273, 17753}, + { 368, -3266, 17509}, + { 369, -3257, 17264}, + { 371, -3247, 17018}, + { 372, -3235, 16772}, + { 372, -3222, 16525}, + { 373, -3208, 16277}, + { 373, -3192, 16028}, + { 373, -3175, 15779}, + { 373, -3157, 15529}, + { 372, -3138, 15279}, + { 371, -3117, 15028}, + { 370, -3095, 14777}, + { 369, -3072, 14526}, + { 368, -3048, 14274}, + { 366, -3022, 14022}, + { 364, -2996, 13770}, + { 362, -2968, 13517}, + { 359, -2940, 13265}, + { 357, -2910, 13012}, + { 354, -2880, 12760}, + { 351, -2848, 12508}, + { 348, -2815, 12255}, + { 344, -2782, 12003}, + { 341, -2747, 11751}, + { 337, -2712, 11500}, + { 333, -2676, 11248}, + { 328, -2639, 10997}, + { 324, -2601, 10747}, + { 320, -2562, 10497}, + { 315, -2523, 10247}, + { 310, -2482, 9998}, + { 305, -2442, 9750}, + { 300, -2400, 9502}, + { 294, -2358, 9255}, + { 289, -2315, 9009}, + { 283, -2271, 8763}, + { 277, -2227, 8519}, + { 271, -2182, 8275}, + { 265, -2137, 8032}, + { 259, -2091, 7791}, + { 252, -2045, 7550}, + { 246, -1998, 7311}, + { 239, -1951, 7072}, + { 232, -1904, 6835}, + { 226, -1856, 6599}, + { 219, -1807, 6364}, + { 212, -1758, 6131}, + { 204, -1709, 5899}, + { 197, -1660, 5668}, + { 190, -1611, 5439}, + { 183, -1561, 5212}, + { 175, -1511, 4986}, + { 168, -1460, 4761}, + { 160, -1410, 4538}, + { 152, -1359, 4317}, + { 145, -1309, 4098}, + { 137, -1258, 3880}, + { 129, -1207, 3664}, + { 121, -1156, 3450}, + { 113, -1105, 3238}, + { 105, -1054, 3028}, + { 97, -1003, 2820}, + { 89, -952, 2614}, + { 81, -901, 2409}, + { 73, -851, 2207}, +}; diff --git a/pkg/silk/csilk/SKP_Silk_resampler_rom.h b/pkg/silk/csilk/SKP_Silk_resampler_rom.h new file mode 100644 index 0000000..8c12f67 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_rom.h @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resample_rom.h * + * * + * Description: Header file for FIR resampling of * + * 32 and 44 kHz input * + * * + * Copyright 2007 (c), Skype Limited * + * All rights reserved. * + * * + * Date: 070807 * + * */ + +#ifndef _SKP_SILK_FIX_RESAMPLER_ROM_H_ +#define _SKP_SILK_FIX_RESAMPLER_ROM_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR 12 +#define RESAMPLER_ORDER_FIR_144 6 + + +/* Tables for 2x downsampler. Values above 32767 intentionally wrap to a negative value. */ +extern const SKP_int16 SKP_Silk_resampler_down2_0; +extern const SKP_int16 SKP_Silk_resampler_down2_1; + +/* Tables for 2x upsampler, low quality. Values above 32767 intentionally wrap to a negative value. */ +extern const SKP_int16 SKP_Silk_resampler_up2_lq_0; +extern const SKP_int16 SKP_Silk_resampler_up2_lq_1; + +/* Tables for 2x upsampler, high quality. Values above 32767 intentionally wrap to a negative value. */ +extern const SKP_int16 SKP_Silk_resampler_up2_hq_0[ 2 ]; +extern const SKP_int16 SKP_Silk_resampler_up2_hq_1[ 2 ]; +extern const SKP_int16 SKP_Silk_resampler_up2_hq_notch[ 4 ]; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const SKP_int16 SKP_Silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_3_8_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR / 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; +extern const SKP_int16 SKP_Silk_Resampler_1_3_COEFS_LQ[ 2 + 3 ]; + +/* Tables with coefficients for 4th order ARMA filter */ +extern const SKP_int16 SKP_Silk_Resampler_320_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_240_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_160_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_120_441_ARMA4_COEFS[ 7 ]; +extern const SKP_int16 SKP_Silk_Resampler_80_441_ARMA4_COEFS[ 7 ]; + +/* Table with interplation fractions of 1/288 : 2/288 : 287/288 (432 Words) */ +extern const SKP_int16 SKP_Silk_resampler_frac_FIR_144[ 144 ][ RESAMPLER_ORDER_FIR_144 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif // _SKP_SILK_FIX_RESAMPLER_ROM_H_ diff --git a/pkg/silk/csilk/SKP_Silk_resampler_structs.h b/pkg/silk/csilk/SKP_Silk_resampler_structs.h new file mode 100644 index 0000000..743c992 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_structs.h @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * File Name: SKP_Silk_resampler_structs.h * + * * + * Description: Structs for IIR/FIR resamplers * + * * + * Copyright 2010 (c), Skype Limited * + * All rights reserved. * + * * + * */ + +#ifndef SKP_Silk_RESAMPLER_STRUCTS_H +#define SKP_Silk_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Flag to enable support for input/output sampling rates above 48 kHz. Turn off for embedded devices */ +#define RESAMPLER_SUPPORT_ABOVE_48KHZ 1 + +#define SKP_Silk_RESAMPLER_MAX_FIR_ORDER 16 +#define SKP_Silk_RESAMPLER_MAX_IIR_ORDER 6 + + +typedef struct _SKP_Silk_resampler_state_struct{ + SKP_int32 sIIR[ SKP_Silk_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + SKP_int32 sFIR[ SKP_Silk_RESAMPLER_MAX_FIR_ORDER ]; + SKP_int32 sDown2[ 2 ]; + void (*resampler_function)( void *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + void (*up2_function)( SKP_int32 *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + SKP_int32 batchSize; + SKP_int32 invRatio_Q16; + SKP_int32 FIR_Fracs; + SKP_int32 input2x; + const SKP_int16 *Coefs; +#if RESAMPLER_SUPPORT_ABOVE_48KHZ + SKP_int32 sDownPre[ 2 ]; + SKP_int32 sUpPost[ 2 ]; + void (*down_pre_function)( SKP_int32 *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + void (*up_post_function)( SKP_int32 *, SKP_int16 *, const SKP_int16 *, SKP_int32 ); + SKP_int32 batchSizePrePost; + SKP_int32 ratio_Q16; + SKP_int32 nPreDownsamplers; + SKP_int32 nPostUpsamplers; +#endif + SKP_int32 magic_number; +} SKP_Silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SKP_Silk_RESAMPLER_STRUCTS_H */ + diff --git a/pkg/silk/csilk/SKP_Silk_resampler_up2.c b/pkg/silk/csilk/SKP_Silk_resampler_up2.c new file mode 100644 index 0000000..9ede6a9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_up2.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_resampler_up2.c * + * * + * Upsample by a factor 2, low quality * + * * + * Copyright 2010 (c), Skype Limited * + * */ + +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_resampler_rom.h" + +/* Upsample by a factor 2, low quality */ +#if EMBEDDED_ARM<5 +void SKP_Silk_resampler_up2( + SKP_int32 *S, /* I/O: State vector [ 2 ] */ + SKP_int16 *out, /* O: Output signal [ 2 * len ] */ + const SKP_int16 *in, /* I: Input signal [ len ] */ + SKP_int32 len /* I: Number of input samples */ +) +{ + SKP_int32 k; + SKP_int32 in32, out32, Y, X; + + SKP_assert( SKP_Silk_resampler_up2_lq_0 > 0 ); + SKP_assert( SKP_Silk_resampler_up2_lq_1 < 0 ); + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = SKP_LSHIFT( (SKP_int32)in[ k ], 10 ); + + /* All-pass section for even output sample */ + Y = SKP_SUB32( in32, S[ 0 ] ); + X = SKP_SMULWB( Y, SKP_Silk_resampler_up2_lq_0 ); + out32 = SKP_ADD32( S[ 0 ], X ); + S[ 0 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out[ 2 * k ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + + /* All-pass section for odd output sample */ + Y = SKP_SUB32( in32, S[ 1 ] ); + X = SKP_SMLAWB( Y, Y, SKP_Silk_resampler_up2_lq_1 ); + out32 = SKP_ADD32( S[ 1 ], X ); + S[ 1 ] = SKP_ADD32( in32, X ); + + /* Convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( out32, 10 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c b/pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c new file mode 100644 index 0000000..60ee2a5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +SKP_int32 SKP_Silk_residual_energy16_covar_FIX( + const SKP_int16 *c, /* I Prediction vector */ + const SKP_int32 *wXX, /* I Correlation matrix */ + const SKP_int32 *wXx, /* I Correlation vector */ + SKP_int32 wxx, /* I Signal energy */ + SKP_int D, /* I Dimension */ + SKP_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + SKP_int i, j, lshifts, Qxtra; + SKP_int32 c_max, w_max, tmp, tmp2, nrg; + SKP_int cn[ MAX_MATRIX_SIZE ]; + const SKP_int32 *pRow; + + /* Safety checks */ + SKP_assert( D >= 0 ); + SKP_assert( D <= 16 ); + SKP_assert( cQ > 0 ); + SKP_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = SKP_max_32( c_max, SKP_abs( ( SKP_int32 )c[ i ] ) ); + } + Qxtra = SKP_min_int( Qxtra, SKP_Silk_CLZ32( c_max ) - 17 ); + + w_max = SKP_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = SKP_min_int( Qxtra, SKP_Silk_CLZ32( SKP_MUL( D, SKP_RSHIFT( SKP_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = SKP_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = SKP_LSHIFT( ( SKP_int )c[ i ], Qxtra ); + SKP_assert( SKP_abs(cn[i]) <= ( SKP_int16_MAX + 1 ) ); /* Check that SKP_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = SKP_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = SKP_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 = SKP_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = SKP_SMLAWB( tmp, SKP_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = SKP_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = SKP_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 > SKP_RSHIFT( SKP_int32_MAX, lshifts + 2 ) ) { + nrg = SKP_int32_MAX >> 1; + } else { + nrg = SKP_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c b/pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c new file mode 100644 index 0000000..f422e55 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void SKP_Silk_residual_energy_FIX( + SKP_int32 nrgs[ NB_SUBFR ], /* O Residual energy per subframe */ + SKP_int nrgsQ[ NB_SUBFR ], /* O Q value per subframe */ + const SKP_int16 x[], /* I Input signal */ + SKP_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ],/* I AR coefs for each frame half */ + const SKP_int32 gains[ NB_SUBFR ], /* I Quantization gains */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int offset, i, j, rshift, lz1, lz2; + SKP_int16 *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + const SKP_int16 *x_ptr; + SKP_int16 S[ MAX_LPC_ORDER ]; + SKP_int32 tmp32; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + for( i = 0; i < 2; i++ ) { + /* Calculate half frame LPC residual signal including preceeding samples */ + SKP_memset( S, 0, LPC_order * sizeof( SKP_int16 ) ); + SKP_Silk_LPC_analysis_filter( x_ptr, a_Q12[ i ], S, LPC_res, ( NB_SUBFR >> 1 ) * offset, LPC_order ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + SKP_Silk_sum_sqr_shift( &nrgs[ i * ( NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < NB_SUBFR; i++ ) { + /* Fully upscale gains and energies */ + lz1 = SKP_Silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = SKP_Silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = SKP_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = SKP_SMMUL( tmp32, tmp32 ); // Q( 2 * lz2 - 32 ) + + /* Scale energies */ + nrgs[ i ] = SKP_SMMUL( tmp32, SKP_LSHIFT32( nrgs[ i ], lz1 ) ); // Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 ) + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c b/pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c new file mode 100644 index 0000000..9d6f8c3 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c @@ -0,0 +1,45 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Copy and multiply a vector by a constant */ +void SKP_Silk_scale_copy_vector16( + SKP_int16 *data_out, + const SKP_int16 *data_in, + SKP_int32 gain_Q16, /* (I): gain in Q16 */ + const SKP_int dataSize /* (I): length */ +) +{ + SKP_int i; + SKP_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = SKP_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (SKP_int16)SKP_CHECK_FIT16( tmp32 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_scale_vector.c b/pkg/silk/csilk/SKP_Silk_scale_vector.c new file mode 100644 index 0000000..320e94a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_scale_vector.c @@ -0,0 +1,43 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.h" + +/* Multiply a vector by a constant */ +void SKP_Silk_scale_vector32_Q26_lshift_18( + SKP_int32 *data1, /* (I/O): Q0/Q18 */ + SKP_int32 gain_Q26, /* (I): Q26 */ + SKP_int dataSize /* (I): length */ +) +{ + SKP_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (SKP_int32)SKP_CHECK_FIT32( SKP_RSHIFT64( SKP_SMULL( data1[ i ], gain_Q26 ), 8 ) );// OUTPUT: Q18 + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_schur.c b/pkg/silk/csilk/SKP_Silk_schur.c new file mode 100644 index 0000000..b631851 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_schur.c @@ -0,0 +1,94 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_schur.c * + * * + * Calculates the reflection coefficients from the correlation sequence * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +SKP_int32 SKP_Silk_schur( /* O: Returns residual energy */ + SKP_int16 *rc_Q15, /* O: reflection coefficients [order] Q15 */ + const SKP_int32 *c, /* I: correlations [order+1] */ + const SKP_int32 order /* I: prediction order */ +) +{ + SKP_int k, n, lz; + SKP_int32 C[ SKP_Silk_MAX_ORDER_LPC + 1 ][ 2 ]; + SKP_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + /* Get number of leading zeros */ + lz = SKP_Silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = SKP_RSHIFT( c[ k ], 1 ); + } + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = SKP_LSHIFT( c[k], lz ); + } + } else { + /* No need to shift */ + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } + } + + for( k = 0; k < order; k++ ) { + + /* Get reflection coefficient */ + rc_tmp_Q15 = -SKP_DIV32_16( C[ k + 1 ][ 0 ], SKP_max_32( SKP_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = SKP_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (SKP_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 ] = SKP_SMLAWB( Ctmp1, SKP_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = SKP_SMLAWB( Ctmp2, SKP_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + /* return residual energy */ + return C[0][1]; +} diff --git a/pkg/silk/csilk/SKP_Silk_schur64.c b/pkg/silk/csilk/SKP_Silk_schur64.c new file mode 100644 index 0000000..c4e824c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_schur64.c @@ -0,0 +1,82 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_schur64.c * + * * + * Calculates the reflection coefficients from the correlation sequence * + * using extra precision * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +#if EMBEDDED_ARM<6 +SKP_int32 SKP_Silk_schur64( /* O: Returns residual energy */ + SKP_int32 rc_Q16[], /* O: Reflection coefficients [order] Q16 */ + const SKP_int32 c[], /* I: Correlations [order+1] */ + SKP_int32 order /* I: Prediction order */ +) +{ + SKP_int k, n; + SKP_int32 C[ SKP_Silk_MAX_ORDER_LPC + 1 ][ 2 ]; + SKP_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + SKP_memset( rc_Q16, 0, order * sizeof( SKP_int32 ) ); + return 0; + } + + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = SKP_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = SKP_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 + SKP_SMMUL( SKP_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + SKP_SMMUL( SKP_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + return C[ 0 ][ 1 ]; +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_setup_complexity.h b/pkg/silk/csilk/SKP_Silk_setup_complexity.h new file mode 100644 index 0000000..f00ab55 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_setup_complexity.h @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" +#include "SKP_Silk_tuning_parameters.h" + +SKP_INLINE SKP_int SKP_Silk_setup_complexity( + SKP_Silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + SKP_int Complexity /* I Complexity (0->low; 1->medium; 2->high) */ +) +{ + SKP_int ret = SKP_SILK_NO_ERROR; + + /* Check that settings are valid */ + if( LOW_COMPLEXITY_ONLY && Complexity != 0 ) { + ret = SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + /* Set encoding complexity */ + if( Complexity == 0 || LOW_COMPLEXITY_ONLY ) { + /* Low complexity */ + psEncC->Complexity = 0; + psEncC->pitchEstimationComplexity = PITCH_EST_COMPLEXITY_LC_MODE; + psEncC->pitchEstimationThreshold_Q16 = SKP_FIX_CONST( FIND_PITCH_CORRELATION_THRESHOLD_LC_MODE, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 8; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 1; + psEncC->NLSF_MSVQ_Survivors = MAX_NLSF_MSVQ_SURVIVORS_LC_MODE; + psEncC->warping_Q16 = 0; + } else if( Complexity == 1 ) { + /* Medium complexity */ + psEncC->Complexity = 1; + psEncC->pitchEstimationComplexity = PITCH_EST_COMPLEXITY_MC_MODE; + psEncC->pitchEstimationThreshold_Q16 = SKP_FIX_CONST( FIND_PITCH_CORRELATION_THRESHOLD_MC_MODE, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = MAX_NLSF_MSVQ_SURVIVORS_MC_MODE; + psEncC->warping_Q16 = psEncC->fs_kHz * SKP_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity == 2 ) { + /* High complexity */ + psEncC->Complexity = 2; + psEncC->pitchEstimationComplexity = PITCH_EST_COMPLEXITY_HC_MODE; + psEncC->pitchEstimationThreshold_Q16 = SKP_FIX_CONST( FIND_PITCH_CORRELATION_THRESHOLD_HC_MODE, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = MAX_NLSF_MSVQ_SURVIVORS; + psEncC->warping_Q16 = psEncC->fs_kHz * SKP_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + ret = SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = SKP_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = 5 * psEncC->fs_kHz + 2 * psEncC->la_shape; + + SKP_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + SKP_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + SKP_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + SKP_assert( psEncC->warping_Q16 <= 32767 ); + SKP_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + SKP_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + + return( ret ); +} diff --git a/pkg/silk/csilk/SKP_Silk_shell_coder.c b/pkg/silk/csilk/SKP_Silk_shell_coder.c new file mode 100644 index 0000000..0163ab4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_shell_coder.c @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +SKP_INLINE void combine_pulses( + SKP_int *out, /* O: combined pulses vector [len] */ + const SKP_int *in, /* I: input vector [2 * len] */ + const SKP_int len /* I: number of OUTPUT samples */ +) +{ + SKP_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +SKP_INLINE void encode_split( + SKP_Silk_range_coder_state *sRC, /* I/O: compressor data structure */ + const SKP_int p_child1, /* I: pulse amplitude of first child subframe */ + const SKP_int p, /* I: pulse amplitude of current subframe */ + const SKP_uint16 *shell_table /* I: table of shell cdfs */ +) +{ + const SKP_uint16 *cdf; + + if( p > 0 ) { + cdf = &shell_table[ SKP_Silk_shell_code_table_offsets[ p ] ]; + SKP_Silk_range_encoder( sRC, p_child1, cdf ); + } +} + +SKP_INLINE void decode_split( + SKP_int *p_child1, /* O: pulse amplitude of first child subframe */ + SKP_int *p_child2, /* O: pulse amplitude of second child subframe */ + SKP_Silk_range_coder_state *sRC, /* I/O: compressor data structure */ + const SKP_int p, /* I: pulse amplitude of current subframe */ + const SKP_uint16 *shell_table /* I: table of shell cdfs */ +) +{ + SKP_int cdf_middle; + const SKP_uint16 *cdf; + + if( p > 0 ) { + cdf_middle = SKP_RSHIFT( p, 1 ); + cdf = &shell_table[ SKP_Silk_shell_code_table_offsets[ p ] ]; + SKP_Silk_range_decoder( p_child1, sRC, cdf, cdf_middle ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_encoder( + SKP_Silk_range_coder_state *sRC, /* I/O compressor data structure */ + const SKP_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + SKP_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + SKP_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( sRC, pulses3[ 0 ], pulses4[ 0 ], SKP_Silk_shell_code_table3 ); + + encode_split( sRC, pulses2[ 0 ], pulses3[ 0 ], SKP_Silk_shell_code_table2 ); + + encode_split( sRC, pulses1[ 0 ], pulses2[ 0 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 0 ], pulses1[ 0 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 2 ], pulses1[ 1 ], SKP_Silk_shell_code_table0 ); + + encode_split( sRC, pulses1[ 2 ], pulses2[ 1 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 4 ], pulses1[ 2 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 6 ], pulses1[ 3 ], SKP_Silk_shell_code_table0 ); + + encode_split( sRC, pulses2[ 2 ], pulses3[ 1 ], SKP_Silk_shell_code_table2 ); + + encode_split( sRC, pulses1[ 4 ], pulses2[ 2 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 8 ], pulses1[ 4 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 10 ], pulses1[ 5 ], SKP_Silk_shell_code_table0 ); + + encode_split( sRC, pulses1[ 6 ], pulses2[ 3 ], SKP_Silk_shell_code_table1 ); + encode_split( sRC, pulses0[ 12 ], pulses1[ 6 ], SKP_Silk_shell_code_table0 ); + encode_split( sRC, pulses0[ 14 ], pulses1[ 7 ], SKP_Silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void SKP_Silk_shell_decoder( + SKP_int *pulses0, /* O data: nonnegative pulse amplitudes */ + SKP_Silk_range_coder_state *sRC, /* I/O compressor data structure */ + const SKP_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + SKP_int pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + SKP_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], sRC, pulses4, SKP_Silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], sRC, pulses3[ 0 ], SKP_Silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], sRC, pulses2[ 0 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], sRC, pulses1[ 0 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], sRC, pulses1[ 1 ], SKP_Silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], sRC, pulses2[ 1 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], sRC, pulses1[ 2 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], sRC, pulses1[ 3 ], SKP_Silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], sRC, pulses3[ 1 ], SKP_Silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], sRC, pulses2[ 2 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], sRC, pulses1[ 4 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], sRC, pulses1[ 5 ], SKP_Silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], sRC, pulses2[ 3 ], SKP_Silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], sRC, pulses1[ 6 ], SKP_Silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], sRC, pulses1[ 7 ], SKP_Silk_shell_code_table0 ); +} diff --git a/pkg/silk/csilk/SKP_Silk_sigm_Q15.c b/pkg/silk/csilk/SKP_Silk_sigm_Q15.c new file mode 100644 index 0000000..6a104ab --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_sigm_Q15.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_sigm_Q15.c * + * * + * Approximate sigmoid function * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" +#if EMBEDDED_ARM<4 +/********************************/ +/* approximate sigmoid function */ +/********************************/ +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const SKP_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const SKP_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const SKP_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +SKP_int SKP_Silk_sigm_Q15( SKP_int in_Q5 ) +{ + SKP_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = SKP_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - SKP_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = SKP_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + SKP_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c b/pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c new file mode 100644 index 0000000..7f026ec --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c @@ -0,0 +1,241 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/*****************************/ +/* Internal function headers */ +/*****************************/ + +typedef struct { + SKP_int32 Q36_part; + SKP_int32 Q48_part; +} inv_D_t; + +/* Factorize square matrix A into LDL form */ +SKP_INLINE void SKP_Silk_LDL_factorize_FIX( + SKP_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + SKP_int M, /* I Size of Matrix */ + SKP_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +); + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveFirst_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +); + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveLast_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +); + +SKP_INLINE void SKP_Silk_LS_divide_Q16_FIX( + SKP_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + SKP_int M /* I dimension */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void SKP_Silk_solve_LDL_FIX( + SKP_int32 *A, /* I Pointer to symetric square matrix A */ + SKP_int M, /* I Size of matrix */ + const SKP_int32 *b, /* I Pointer to b vector */ + SKP_int32 *x_Q16 /* O Pointer to x solution vector */ +) +{ + SKP_int32 L_Q16[ MAX_MATRIX_SIZE * MAX_MATRIX_SIZE ]; + SKP_int32 Y[ MAX_MATRIX_SIZE ]; + inv_D_t inv_D[ MAX_MATRIX_SIZE ]; + + SKP_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*L', + where L is lower triangular with ones on diagonal + ****************************************************/ + SKP_Silk_LDL_factorize_FIX( A, M, L_Q16, inv_D ); + + /**************************************************** + * substitute D*L'*x = Y. ie: + L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b + ******************************************************/ + SKP_Silk_LS_SolveFirst_FIX( L_Q16, M, b, Y ); + + /**************************************************** + D*L'*x = Y <=> L'*x = inv(D)*Y, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + SKP_Silk_LS_divide_Q16_FIX( Y, inv_D, M ); + + /**************************************************** + x = inv(L') * inv(D) * Y + *****************************************************/ + SKP_Silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 ); +} + +SKP_INLINE void SKP_Silk_LDL_factorize_FIX( + SKP_int32 *A, /* I Pointer to Symetric Square Matrix */ + SKP_int M, /* I Size of Matrix */ + SKP_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +) +{ + SKP_int i, j, k, status, loop_count; + const SKP_int32 *ptr1, *ptr2; + SKP_int32 diag_min_value, tmp_32, err; + SKP_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ]; + SKP_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48; + + SKP_assert( M <= MAX_MATRIX_SIZE ); + + status = 1; + diag_min_value = SKP_max_32( SKP_SMMUL( SKP_ADD_SAT32( A[ 0 ], A[ SKP_SMULBB( M, M ) - 1 ] ), SKP_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 ); + for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) { + status = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L_Q16, j, 0, M ); + tmp_32 = 0; + for( i = 0; i < j; i++ ) { + v_Q0[ i ] = SKP_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */ + tmp_32 = SKP_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */ + } + tmp_32 = SKP_SUB32( matrix_ptr( A, j, j, M ), tmp_32 ); + + if( tmp_32 < diag_min_value ) { + tmp_32 = SKP_SUB32( SKP_SMULBB( loop_count + 1, diag_min_value ), tmp_32 ); + /* Matrix not positive semi-definite, or ill conditioned */ + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) = SKP_ADD32( matrix_ptr( A, i, i, M ), tmp_32 ); + } + status = 1; + break; + } + D_Q0[ j ] = tmp_32; /* always < max(Correlation) */ + + /* two-step division */ + one_div_diag_Q36 = SKP_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */ + one_div_diag_Q40 = SKP_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */ + err = SKP_SUB32( 1 << 24, SKP_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */ + one_div_diag_Q48 = SKP_SMULWW( err, one_div_diag_Q40 ); /* Q48 */ + + /* Save 1/Ds */ + inv_D[ j ].Q36_part = one_div_diag_Q36; + inv_D[ j ].Q48_part = one_div_diag_Q48; + + matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */ + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L_Q16, j + 1, 0, M ); + for( i = j + 1; i < M; i++ ) { + tmp_32 = 0; + for( k = 0; k < j; k++ ) { + tmp_32 = SKP_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */ + } + tmp_32 = SKP_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */ + + /* tmp_32 / D_Q0[j] : Divide to Q16 */ + matrix_ptr( L_Q16, i, j, M ) = SKP_ADD32( SKP_SMMUL( tmp_32, one_div_diag_Q48 ), + SKP_RSHIFT( SKP_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + + /* go to next column */ + ptr2 += M; + } + } + } + + SKP_assert( status == 0 ); +} + +SKP_INLINE void SKP_Silk_LS_divide_Q16_FIX( + SKP_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + SKP_int M /* I Order */ +) +{ + SKP_int i; + SKP_int32 tmp_32; + SKP_int32 one_div_diag_Q36, one_div_diag_Q48; + + for( i = 0; i < M; i++ ) { + one_div_diag_Q36 = inv_D[ i ].Q36_part; + one_div_diag_Q48 = inv_D[ i ].Q48_part; + + tmp_32 = T[ i ]; + T[ i ] = SKP_ADD32( SKP_SMMUL( tmp_32, one_div_diag_Q48 ), SKP_RSHIFT( SKP_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + } +} + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveFirst_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +) +{ + SKP_int i, j; + const SKP_int32 *ptr32; + SKP_int32 tmp_32; + + for( i = 0; i < M; i++ ) { + ptr32 = matrix_adr( L_Q16, i, 0, M ); + tmp_32 = 0; + for( j = 0; j < i; j++ ) { + tmp_32 = SKP_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] ); + } + x_Q16[ i ] = SKP_SUB32( b[ i ], tmp_32 ); + } +} + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveLast_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +) +{ + SKP_int i, j; + const SKP_int32 *ptr32; + SKP_int32 tmp_32; + + for( i = M - 1; i >= 0; i-- ) { + ptr32 = matrix_adr( L_Q16, 0, i, M ); + tmp_32 = 0; + for( j = M - 1; j > i; j-- ) { + tmp_32 = SKP_SMLAWW( tmp_32, ptr32[ SKP_SMULBB( j, M ) ], x_Q16[ j ] ); + } + x_Q16[ i ] = SKP_SUB32( b[ i ], tmp_32 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_sort.c b/pkg/silk/csilk/SKP_Silk_sort.c new file mode 100644 index 0000000..3753c7b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_sort.c @@ -0,0 +1,147 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ + +#include "SKP_Silk_SigProc_FIX.h" + +void SKP_Silk_insertion_sort_increasing( + SKP_int32 *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted output positions */ +) +{ + SKP_int32 value; + SKP_int i, j; + + /* Safety checks */ + SKP_assert( K > 0 ); + SKP_assert( L > 0 ); + SKP_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + index[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + } +} + +void SKP_Silk_insertion_sort_decreasing_int16( + SKP_int16 *a, /* I/O: Unsorted / Sorted vector */ + SKP_int *index, /* O: Index vector for the sorted elements */ + const SKP_int L, /* I: Vector length */ + const SKP_int K /* I: Number of correctly sorted output positions */ +) +{ + SKP_int i, j; + SKP_int value; + + /* Safety checks */ + SKP_assert( K > 0 ); + SKP_assert( L > 0 ); + SKP_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + index[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + index[ j + 1 ] = index[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + index[ j + 1 ] = i; /* Write index */ + } + } +} + +void SKP_Silk_insertion_sort_increasing_all_values( + SKP_int *a, /* I/O: Unsorted / Sorted vector */ + const SKP_int L /* I: Vector length */ +) +{ + SKP_int value; + SKP_int i, j; + + /* Safety checks */ + SKP_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} + + diff --git a/pkg/silk/csilk/SKP_Silk_structs.h b/pkg/silk/csilk/SKP_Silk_structs.h new file mode 100644 index 0000000..4cb1db5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_structs.h @@ -0,0 +1,353 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_STRUCTS_H +#define SKP_SILK_STRUCTS_H + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + SKP_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + SKP_int32 sLTP_shp_Q10[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 sLPC_Q14[ MAX_FRAME_LENGTH / NB_SUBFR + NSQ_LPC_BUF_LENGTH ]; + SKP_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 sLF_AR_shp_Q12; + SKP_int lagPrev; + SKP_int sLTP_buf_idx; + SKP_int sLTP_shp_buf_idx; + SKP_int32 rand_seed; + SKP_int32 prev_inv_gain_Q16; + SKP_int rewhite_flag; +} SKP_Silk_nsq_state; /* FIX*/ + +/* Struct for Low BitRate Redundant (LBRR) information */ +typedef struct { + SKP_uint8 payload[ MAX_ARITHM_BYTES ]; + SKP_int nBytes; /* Number of bytes in payload */ + SKP_int usage; /* Tells how the payload should be used as FEC */ +} SKP_SILK_LBRR_struct; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + SKP_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + SKP_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + SKP_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + SKP_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + SKP_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + SKP_int16 HPstate; /* State of differentiator in the lowest band */ + SKP_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + SKP_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + SKP_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + SKP_int32 counter; /* Frame counter used in the initial phase */ +} SKP_Silk_VAD_state; + +/*******************************/ +/* Range encoder/decoder state */ +/*******************************/ +typedef struct { + SKP_int32 bufferLength; + SKP_int32 bufferIx; + SKP_uint32 base_Q32; + SKP_uint32 range_Q16; + SKP_int32 error; + SKP_uint8 buffer[ MAX_ARITHM_BYTES ]; /* Buffer containing payload */ +} SKP_Silk_range_coder_state; + +/* Input frequency range detection struct */ +typedef struct { + SKP_int32 S_HP_8_kHz[ NB_SOS ][ 2 ]; /* HP filter State */ + SKP_int32 ConsecSmplsAboveThres; + SKP_int32 ActiveSpeech_ms; /* Accumulated time with active speech */ + SKP_int SWB_detected; /* Flag to indicate SWB input */ + SKP_int WB_detected; /* Flag to indicate WB input */ +} SKP_Silk_detect_SWB_state; + +#if SWITCH_TRANSITION_FILTERING +/* Variable cut-off low-pass filter state */ +typedef struct { + SKP_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + SKP_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + SKP_int mode; /* Operating mode, 0: switch down, 1: switch up */ +} SKP_Silk_LP_state; +#endif + +/* Structure for one stage of MSVQ */ +typedef struct { + const SKP_int32 nVectors; + const SKP_int16 *CB_NLSF_Q15; + const SKP_int16 *Rates_Q5; +} SKP_Silk_NLSF_CBS; + +/* Structure containing NLSF MSVQ codebook */ +typedef struct { + const SKP_int32 nStages; + + /* Fields for (de)quantizing */ + const SKP_Silk_NLSF_CBS *CBStages; + const SKP_int *NDeltaMin_Q15; + + /* Fields for arithmetic (de)coding */ + const SKP_uint16 *CDF; + const SKP_uint16 * const *StartPtr; + const SKP_int *MiddleIx; +} SKP_Silk_NLSF_CB_struct; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + SKP_Silk_range_coder_state sRC; /* Range coder state */ + SKP_Silk_range_coder_state sRC_LBRR; /* Range coder state (for low bitrate redundancy) */ + SKP_Silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + SKP_Silk_nsq_state sNSQ_LBRR; /* Noise Shape Quantizer State ( for low bitrate redundancy ) */ + +#if HIGH_PASS_INPUT + SKP_int32 In_HP_State[ 2 ]; /* High pass filter state */ +#endif +#if SWITCH_TRANSITION_FILTERING + SKP_Silk_LP_state sLP; /* Low pass filter state */ +#endif + SKP_Silk_VAD_state sVAD; /* Voice activity detector state */ + + SKP_int LBRRprevLastGainIndex; + SKP_int prev_sigtype; + SKP_int typeOffsetPrev; /* Previous signal type and quantization offset */ + SKP_int prevLag; + SKP_int prev_lagIndex; + SKP_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + SKP_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + SKP_int maxInternal_fs_kHz; /* Maximum internal sampling frequency (kHz) */ + SKP_int fs_kHz; /* Internal sampling frequency (kHz) */ + SKP_int fs_kHz_changed; /* Did we switch yet? */ + SKP_int frame_length; /* Frame length (samples) */ + SKP_int subfr_length; /* Subframe length (samples) */ + SKP_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + SKP_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + SKP_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + SKP_int32 TargetRate_bps; /* Target bitrate (bps) */ + SKP_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + SKP_int PacketLoss_perc; /* Packet loss rate measured by farend */ + SKP_int32 frameCounter; + SKP_int Complexity; /* Complexity setting: 0-> low; 1-> medium; 2->high */ + SKP_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + SKP_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + SKP_int shapingLPCOrder; /* Filter order for noise shaping filters */ + SKP_int predictLPCOrder; /* Filter order for prediction filters */ + SKP_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + SKP_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + SKP_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + SKP_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */ + SKP_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + SKP_int first_frame_after_reset; /* Flag for deactivating NLSF interp. and fluc. reduction after resets */ + SKP_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + SKP_int warping_Q16; /* Warping parameter for warped noise shaping */ + + /* Input/output buffering */ + SKP_int16 inputBuf[ MAX_FRAME_LENGTH ]; /* buffer containin input signal */ + SKP_int inputBufIx; + SKP_int nFramesInPayloadBuf; /* number of frames sitting in outputBuf */ + SKP_int nBytesInPayloadBuf; /* number of bytes sitting in outputBuf */ + + /* Parameters For LTP scaling Control */ + SKP_int frames_since_onset; + + const SKP_Silk_NLSF_CB_struct *psNLSF_CB[ 2 ]; /* Pointers to voiced/unvoiced NLSF codebooks */ + + /* Struct for Inband LBRR */ + SKP_SILK_LBRR_struct LBRR_buffer[ MAX_LBRR_DELAY ]; + SKP_int oldest_LBRR_idx; + SKP_int useInBandFEC; /* Saves the API setting for query */ + SKP_int LBRR_enabled; + SKP_int LBRR_GainIncreases; /* Number of shifts to Gains to get LBRR rate Voiced frames */ + + /* Bitrate control */ + SKP_int32 bitrateDiff; /* Accumulated diff. between the target bitrate and the switch bitrates */ + SKP_int32 bitrate_threshold_up; /* Threshold for switching to a higher internal sample frequency */ + SKP_int32 bitrate_threshold_down; /* Threshold for switching to a lower internal sample frequency */ + + SKP_Silk_resampler_state_struct resampler_state; + + /* DTX */ + SKP_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + SKP_int useDTX; /* Flag to enable DTX */ + SKP_int inDTX; /* Flag to signal DTX period */ + SKP_int vadFlag; /* Flag to indicate Voice Activity */ + + /* Struct for detecting SWB input */ + SKP_Silk_detect_SWB_state sSWBdetect; + + + /* Buffers */ + SKP_int8 q[ MAX_FRAME_LENGTH ]; /* pulse signal buffer */ + SKP_int8 q_LBRR[ MAX_FRAME_LENGTH ]; /* pulse signal buffer */ + +} SKP_Silk_encoder_state; + + +/************************/ +/* Encoder control */ +/************************/ +typedef struct { + /* Quantization indices */ + SKP_int lagIndex; + SKP_int contourIndex; + SKP_int PERIndex; + SKP_int LTPIndex[ NB_SUBFR ]; + SKP_int NLSFIndices[ NLSF_MSVQ_MAX_CB_STAGES ]; /* NLSF path of quantized LSF vector */ + SKP_int NLSFInterpCoef_Q2; + SKP_int GainsIndices[ NB_SUBFR ]; + SKP_int32 Seed; + SKP_int LTP_scaleIndex; + SKP_int RateLevelIndex; + SKP_int QuantOffsetType; + SKP_int sigtype; + + /* Prediction and coding parameters */ + SKP_int pitchL[ NB_SUBFR ]; + + SKP_int LBRR_usage; /* Low bitrate redundancy usage */ +} SKP_Silk_encoder_control; + +/* Struct for Packet Loss Concealment */ +typedef struct { + SKP_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + SKP_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + SKP_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + SKP_int last_frame_lost; /* Was previous frame lost */ + SKP_int32 rand_seed; /* Seed for unvoiced signal generation */ + SKP_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + SKP_int32 conc_energy; + SKP_int conc_energy_shift; + SKP_int16 prevLTP_scale_Q14; + SKP_int32 prevGain_Q16[ NB_SUBFR ]; + SKP_int fs_kHz; +} SKP_Silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + SKP_int32 CNG_exc_buf_Q10[ MAX_FRAME_LENGTH ]; + SKP_int CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + SKP_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + SKP_int32 CNG_smth_Gain_Q16; + SKP_int32 rand_seed; + SKP_int fs_kHz; +} SKP_Silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + SKP_Silk_range_coder_state sRC; /* Range coder state */ + SKP_int32 prev_inv_gain_Q16; + SKP_int32 sLTP_Q16[ 2 * MAX_FRAME_LENGTH ]; + SKP_int32 sLPC_Q14[ MAX_FRAME_LENGTH / NB_SUBFR + MAX_LPC_ORDER ]; + SKP_int32 exc_Q10[ MAX_FRAME_LENGTH ]; + SKP_int32 res_Q10[ MAX_FRAME_LENGTH ]; + SKP_int16 outBuf[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for output signal */ + SKP_int lagPrev; /* Previous Lag */ + SKP_int LastGainIndex; /* Previous gain index */ + SKP_int LastGainIndex_EnhLayer; /* Previous gain index */ + SKP_int typeOffsetPrev; /* Previous signal type and quantization offset */ + SKP_int32 HPState[ DEC_HP_ORDER ]; /* HP filter state */ + const SKP_int16 *HP_A; /* HP filter AR coefficients */ + const SKP_int16 *HP_B; /* HP filter MA coefficients */ + SKP_int fs_kHz; /* Sampling frequency in kHz */ + SKP_int32 prev_API_sampleRate; /* Previous API sample frequency (Hz) */ + SKP_int frame_length; /* Frame length (samples) */ + SKP_int subfr_length; /* Subframe length (samples) */ + SKP_int LPC_order; /* LPC order */ + SKP_int prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + SKP_int first_frame_after_reset; /* Flag for deactivating NLSF interp. and fluc. reduction after resets */ + + /* For buffering payload in case of more frames per packet */ + SKP_int nBytesLeft; + SKP_int nFramesDecoded; + SKP_int nFramesInPacket; + SKP_int moreInternalDecoderFrames; + SKP_int FrameTermination; + + SKP_Silk_resampler_state_struct resampler_state; + + const SKP_Silk_NLSF_CB_struct *psNLSF_CB[ 2 ]; /* Pointers to voiced/unvoiced NLSF codebooks */ + + /* Parameters used to investigate if inband FEC is used */ + SKP_int vadFlag; + SKP_int no_FEC_counter; /* Counts number of frames wo inband FEC */ + SKP_int inband_FEC_offset; /* 0: no FEC, 1: FEC with 1 packet offset, 2: FEC w 2 packets offset */ + + /* CNG state */ + SKP_Silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + SKP_int lossCnt; + SKP_int prev_sigtype; /* Previous sigtype */ + + SKP_Silk_PLC_struct sPLC; + + + +} SKP_Silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* prediction and coding parameters */ + SKP_int pitchL[ NB_SUBFR ]; + SKP_int32 Gains_Q16[ NB_SUBFR ]; + SKP_int32 Seed; + /* holds interpolated and final coefficients, 4-byte aligned */ + SKP_DWORD_ALIGN SKP_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ]; + SKP_int LTP_scale_Q14; + + /* quantization indices */ + SKP_int PERIndex; + SKP_int RateLevelIndex; + SKP_int QuantOffsetType; + SKP_int sigtype; + SKP_int NLSFInterpCoef_Q2; +} SKP_Silk_decoder_control; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_structs_FIX.h b/pkg/silk/csilk/SKP_Silk_structs_FIX.h new file mode 100644 index 0000000..967c90c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_structs_FIX.h @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_STRUCTS_FIX_H +#define SKP_SILK_STRUCTS_FIX_H + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_main.h" +#include "SKP_Silk_structs.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + SKP_int LastGainIndex; + SKP_int32 HarmBoost_smth_Q16; + SKP_int32 HarmShapeGain_smth_Q16; + SKP_int32 Tilt_smth_Q16; +} SKP_Silk_shape_state_FIX; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + SKP_int16 sLTP_shp[ LTP_BUF_LENGTH ]; + SKP_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; // Q14 + SKP_int sLTP_shp_buf_idx; + SKP_int32 sLF_AR_shp_Q12; + SKP_int32 sLF_MA_shp_Q12; + SKP_int sHarmHP; + SKP_int32 rand_seed; + SKP_int lagPrev; +} SKP_Silk_prefilter_state_FIX; + +/*****************************/ +/* Prediction analysis state */ +/*****************************/ +typedef struct { + SKP_int pitch_LPC_win_length; + SKP_int min_pitch_lag; /* Lowest possible pitch lag (samples) */ + SKP_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + SKP_int prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ +} SKP_Silk_predict_state_FIX; + + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + SKP_Silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + +#if HIGH_PASS_INPUT + SKP_int32 variable_HP_smth1_Q15; /* State of first smoother */ + SKP_int32 variable_HP_smth2_Q15; /* State of second smoother */ +#endif + SKP_Silk_shape_state_FIX sShape; /* Shape state */ + SKP_Silk_prefilter_state_FIX sPrefilt; /* Prefilter State */ + SKP_Silk_predict_state_FIX sPred; /* Prediction state */ + + /* Buffer for find pitch and noise shape analysis */ + SKP_DWORD_ALIGN SKP_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ]; + SKP_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator, approx Q15 */ + SKP_int mu_LTP_Q8; /* Rate-distortion tradeoff in LTP quantization */ + SKP_int32 SNR_dB_Q7; /* Quality setting */ + SKP_int32 avgGain_Q16; /* average gain during active speech */ + SKP_int32 avgGain_Q16_one_bit_per_sample; /* average gain during active speech */ + SKP_int BufferedInChannel_ms; /* Simulated number of ms buffer because of exceeded TargetRate_bps */ + SKP_int speech_activity_Q8; /* Speech activity in Q8 */ + + /* Parameters For LTP scaling Control */ + SKP_int prevLTPredCodGain_Q7; + SKP_int HPLTPredCodGain_Q7; + + SKP_int32 inBandFEC_SNR_comp_Q8; /* Compensation to SNR_dB when using inband FEC Voiced */ + +} SKP_Silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + SKP_Silk_encoder_control sCmn; /* Common struct, shared with floating-point code */ + + /* Prediction and coding parameters */ + SKP_int32 Gains_Q16[ NB_SUBFR ]; + SKP_DWORD_ALIGN SKP_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ]; + SKP_int LTP_scale_Q14; + + /* Noise shaping parameters */ + /* Testing */ + SKP_DWORD_ALIGN SKP_int16 AR1_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + SKP_DWORD_ALIGN SKP_int16 AR2_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + SKP_int32 LF_shp_Q14[ NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + SKP_int GainsPre_Q14[ NB_SUBFR ]; + SKP_int HarmBoost_Q14[ NB_SUBFR ]; + SKP_int Tilt_Q14[ NB_SUBFR ]; + SKP_int HarmShapeGain_Q14[ NB_SUBFR ]; + SKP_int Lambda_Q10; + SKP_int input_quality_Q14; + SKP_int coding_quality_Q14; + SKP_int32 pitch_freq_low_Hz; + SKP_int current_SNR_dB_Q7; + + /* measures */ + SKP_int sparseness_Q8; + SKP_int32 predGain_Q16; + SKP_int LTPredCodGain_Q7; + SKP_int input_quality_bands_Q15[ VAD_N_BANDS ]; + SKP_int input_tilt_Q15; + SKP_int32 ResNrg[ NB_SUBFR ]; /* Residual energy per subframe */ + SKP_int ResNrgQ[ NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + +} SKP_Silk_encoder_control_FIX; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c b/pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c new file mode 100644 index 0000000..a67ecbe --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * SKP_Silk_sum_sqr_shift.c * + * * + * compute number of bits to right shift the sum of squares of a vector * + * of int16s to make it fit in an int32 * + * * + * Copyright 2006-2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" +#if (EMBEDDED_ARM<5) +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void SKP_Silk_sum_sqr_shift( + SKP_int32 *energy, /* O Energy of x, after shifting to the right */ + SKP_int *shift, /* O Number of bits right shift applied to energy */ + const SKP_int16 *x, /* I Input vector */ + SKP_int len /* I Length of input vector */ +) +{ + SKP_int i, shft; + SKP_int32 in32, nrg_tmp, nrg; + + if( (SKP_int32)( (SKP_int_ptr_size)x & 2 ) != 0 ) { + /* Input is not 4-byte aligned */ + nrg = SKP_SMULBB( x[ 0 ], x[ 0 ] ); + i = 1; + } else { + nrg = 0; + i = 0; + } + shft = 0; + len--; + while( i < len ) { + /* Load two values at once */ + in32 = *( (SKP_int32 *)&x[ i ] ); + nrg = SKP_SMLABB_ovflw( nrg, in32, in32 ); + nrg = SKP_SMLATT_ovflw( nrg, in32, in32 ); + i += 2; + if( nrg < 0 ) { + /* Scale down */ + nrg = (SKP_int32)SKP_RSHIFT_uint( (SKP_uint32)nrg, 2 ); + shft = 2; + break; + } + } + for( ; i < len; i += 2 ) { + /* Load two values at once */ + in32 = *( (SKP_int32 *)&x[ i ] ); + nrg_tmp = SKP_SMULBB( in32, in32 ); + nrg_tmp = SKP_SMLATT_ovflw( nrg_tmp, in32, in32 ); + nrg = (SKP_int32)SKP_ADD_RSHIFT_uint( nrg, (SKP_uint32)nrg_tmp, shft ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (SKP_int32)SKP_RSHIFT_uint( (SKP_uint32)nrg, 2 ); + shft += 2; + } + } + if( i == len ) { + /* One sample left to process */ + nrg_tmp = SKP_SMULBB( x[ i ], x[ i ] ); + nrg = (SKP_int32)SKP_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + /* Make sure to have at least one extra leading zero (two leading zeros in total) */ + if( nrg & 0xC0000000 ) { + nrg = SKP_RSHIFT_uint( (SKP_uint32)nrg, 2 ); + shft += 2; + } + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_tables.h b/pkg/silk/csilk/SKP_Silk_tables.h new file mode 100644 index 0000000..37613bd --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables.h @@ -0,0 +1,168 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_TABLES_H +#define SKP_SILK_TABLES_H + +#include "SKP_Silk_define.h" +#include "SKP_Silk_structs.h" + +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* entropy coding tables */ +extern const SKP_uint16 SKP_Silk_type_offset_CDF[ 5 ]; /* 5 */ +extern const SKP_uint16 SKP_Silk_type_offset_joint_CDF[ 4 ][ 5 ]; /* 20 */ +extern const SKP_int SKP_Silk_type_offset_CDF_offset; + +extern const SKP_uint16 SKP_Silk_gain_CDF[ 2 ][ N_LEVELS_QGAIN + 1 ]; /* 130 */ +extern const SKP_int SKP_Silk_gain_CDF_offset; +extern const SKP_uint16 SKP_Silk_delta_gain_CDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 2 ]; /* 46 */ +extern const SKP_int SKP_Silk_delta_gain_CDF_offset; + +extern const SKP_uint16 SKP_Silk_pitch_lag_NB_CDF[ 8 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 130 */ +extern const SKP_int SKP_Silk_pitch_lag_NB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_lag_MB_CDF[ 12 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 194 */ +extern const SKP_int SKP_Silk_pitch_lag_MB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_lag_WB_CDF[ 16 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 258 */ +extern const SKP_int SKP_Silk_pitch_lag_WB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_lag_SWB_CDF[ 24 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ]; /* 386 */ +extern const SKP_int SKP_Silk_pitch_lag_SWB_CDF_offset; + +extern const SKP_uint16 SKP_Silk_pitch_contour_CDF[ 35 ]; /* 35 */ +extern const SKP_int SKP_Silk_pitch_contour_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_contour_NB_CDF[ 12 ]; /* 12 */ +extern const SKP_int SKP_Silk_pitch_contour_NB_CDF_offset; +extern const SKP_uint16 SKP_Silk_pitch_delta_CDF[23]; /* 23 */ +extern const SKP_int SKP_Silk_pitch_delta_CDF_offset; + +extern const SKP_uint16 SKP_Silk_pulses_per_block_CDF[ N_RATE_LEVELS ][ MAX_PULSES + 3 ]; /* 210 */ +extern const SKP_int SKP_Silk_pulses_per_block_CDF_offset; +extern const SKP_int16 SKP_Silk_pulses_per_block_BITS_Q6[ N_RATE_LEVELS - 1 ][ MAX_PULSES + 2 ]; /* 180 */ + +extern const SKP_uint16 SKP_Silk_rate_levels_CDF[ 2 ][ N_RATE_LEVELS ]; /* 20 */ +extern const SKP_int SKP_Silk_rate_levels_CDF_offset; +extern const SKP_int16 SKP_Silk_rate_levels_BITS_Q6[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const SKP_int SKP_Silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const SKP_uint16 SKP_Silk_shell_code_table0[ 33 ]; /* 33 */ +extern const SKP_uint16 SKP_Silk_shell_code_table1[ 52 ]; /* 52 */ +extern const SKP_uint16 SKP_Silk_shell_code_table2[ 102 ]; /* 102 */ +extern const SKP_uint16 SKP_Silk_shell_code_table3[ 207 ]; /* 207 */ +extern const SKP_uint16 SKP_Silk_shell_code_table_offsets[ 19 ]; /* 19 */ + +extern const SKP_uint16 SKP_Silk_lsb_CDF[ 3 ]; /* 3 */ + +extern const SKP_uint16 SKP_Silk_sign_CDF[ 36 ]; /* 36 */ + +extern const SKP_uint16 SKP_Silk_LTP_per_index_CDF[ 4 ]; /* 4 */ +extern const SKP_int SKP_Silk_LTP_per_index_CDF_offset; +extern const SKP_int16 * const SKP_Silk_LTP_gain_BITS_Q6_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const SKP_uint16 * const SKP_Silk_LTP_gain_CDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const SKP_int SKP_Silk_LTP_gain_CDF_offsets[ NB_LTP_CBKS ]; /* 3 */ +extern const SKP_int32 SKP_Silk_LTP_gain_middle_avg_RD_Q14; +extern const SKP_uint16 SKP_Silk_LTPscale_CDF[ 4 ]; /* 4 */ +extern const SKP_int SKP_Silk_LTPscale_offset; + +/* Tables for LTPScale */ +extern const SKP_int16 SKP_Silk_LTPScales_table_Q14[ 3 ]; + +extern const SKP_uint16 SKP_Silk_vadflag_CDF[ 3 ]; /* 3 */ +extern const SKP_int SKP_Silk_vadflag_offset; + +extern const SKP_int SKP_Silk_SamplingRates_table[ 4 ]; /* 4 */ +extern const SKP_uint16 SKP_Silk_SamplingRates_CDF[ 5 ]; /* 5 */ +extern const SKP_int SKP_Silk_SamplingRates_offset; + +extern const SKP_uint16 SKP_Silk_NLSF_interpolation_factor_CDF[ 6 ]; +extern const SKP_int SKP_Silk_NLSF_interpolation_factor_offset; + +/* NLSF codebooks */ +extern const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_16, SKP_Silk_NLSF_CB1_16; +extern const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_10, SKP_Silk_NLSF_CB1_10; + +/* quantization tables */ +extern const SKP_int16 * const SKP_Silk_LTP_vq_ptrs_Q14[ NB_LTP_CBKS ]; /* 168 */ +extern const SKP_int SKP_Silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +extern const SKP_int32 TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 TargetRate_table_SWB[ TARGET_RATE_TAB_SZ ]; +extern const SKP_int32 SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; + +extern const SKP_int32 SNR_table_one_bit_per_sample_Q7[ 4 ]; + +/* Filter coeficicnts for HP filter: 4. Order filter implementad as two biquad filters */ +extern const SKP_int16 SKP_Silk_SWB_detect_B_HP_Q13[ NB_SOS ][ 3 ]; +extern const SKP_int16 SKP_Silk_SWB_detect_A_HP_Q13[ NB_SOS ][ 2 ]; + +/* Decoder high-pass filter coefficients for 24 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_24[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_24[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Decoder high-pass filter coefficients for 16 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_16[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_16[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Decoder high-pass filter coefficients for 12 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_12[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_12[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Decoder high-pass filter coefficients for 8 kHz sampling */ +extern const SKP_int16 SKP_Silk_Dec_A_HP_8[ DEC_HP_ORDER ]; /* 2 */ +extern const SKP_int16 SKP_Silk_Dec_B_HP_8[ DEC_HP_ORDER + 1 ]; /* 3 */ + +/* Table for frame termination indication */ +extern const SKP_uint16 SKP_Silk_FrameTermination_CDF[ 5 ]; +extern const SKP_int SKP_Silk_FrameTermination_offset; + +/* Table for random seed */ +extern const SKP_uint16 SKP_Silk_Seed_CDF[ 5 ]; +extern const SKP_int SKP_Silk_Seed_offset; + +/* Quantization offsets */ +extern const SKP_int16 SKP_Silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; + +#if SWITCH_TRANSITION_FILTERING +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const SKP_int32 SKP_Silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; +extern const SKP_int32 SKP_Silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_tables_LTP.c b/pkg/silk/csilk/SKP_Silk_tables_LTP.c new file mode 100644 index 0000000..77533ab --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_LTP.c @@ -0,0 +1,324 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_LTP_per_index_CDF[ 4 ] = { + 0, 20992, 40788, 65535 +}; + +const SKP_int SKP_Silk_LTP_per_index_CDF_offset = 1; + + +const SKP_uint16 SKP_Silk_LTP_gain_CDF_0[ 11 ] = { + 0, 49380, 54463, 56494, 58437, 60101, 61683, 62985, + 64066, 64823, 65535 +}; + +const SKP_uint16 SKP_Silk_LTP_gain_CDF_1[ 21 ] = { + 0, 25290, 30654, 35710, 40386, 42937, 45250, 47459, + 49411, 51348, 52974, 54517, 55976, 57423, 58865, 60285, + 61667, 62895, 63827, 64724, 65535 +}; + +const SKP_uint16 SKP_Silk_LTP_gain_CDF_2[ 41 ] = { + 0, 4958, 9439, 13581, 17638, 21651, 25015, 28025, + 30287, 32406, 34330, 36240, 38130, 39790, 41281, 42764, + 44229, 45676, 47081, 48431, 49675, 50849, 51932, 52966, + 53957, 54936, 55869, 56789, 57708, 58504, 59285, 60043, + 60796, 61542, 62218, 62871, 63483, 64076, 64583, 65062, + 65535 +}; + +const SKP_int SKP_Silk_LTP_gain_CDF_offsets[ 3 ] = { + 1, 3, 10 +}; + +const SKP_int32 SKP_Silk_LTP_gain_middle_avg_RD_Q14 = 11010; + +const SKP_int16 SKP_Silk_LTP_gain_BITS_Q6_0[ 10 ] = { + 26, 236, 321, 325, 339, 344, 362, 379, + 412, 418 +}; + +const SKP_int16 SKP_Silk_LTP_gain_BITS_Q6_1[ 20 ] = { + 88, 231, 237, 244, 300, 309, 313, 324, + 325, 341, 346, 351, 352, 352, 354, 356, + 367, 393, 396, 406 +}; + +const SKP_int16 SKP_Silk_LTP_gain_BITS_Q6_2[ 40 ] = { + 238, 248, 255, 257, 258, 274, 284, 311, + 317, 326, 326, 327, 339, 349, 350, 351, + 352, 355, 358, 366, 371, 379, 383, 387, + 388, 393, 394, 394, 407, 409, 412, 412, + 413, 422, 426, 432, 434, 449, 454, 455 +}; + +const SKP_uint16 * const SKP_Silk_LTP_gain_CDF_ptrs[ NB_LTP_CBKS ] = { + SKP_Silk_LTP_gain_CDF_0, + SKP_Silk_LTP_gain_CDF_1, + SKP_Silk_LTP_gain_CDF_2 +}; + +const SKP_int16 * const SKP_Silk_LTP_gain_BITS_Q6_ptrs[ NB_LTP_CBKS ] = { + SKP_Silk_LTP_gain_BITS_Q6_0, + SKP_Silk_LTP_gain_BITS_Q6_1, + SKP_Silk_LTP_gain_BITS_Q6_2 +}; + +const SKP_int16 SKP_Silk_LTP_gain_vq_0_Q14[ 10 ][ 5 ] = +{ +{ + 594, 984, 2840, 1021, 669 +}, +{ + 10, 35, 304, -1, 23 +}, +{ + -694, 1923, 4603, 2975, 2335 +}, +{ + 2437, 3176, 3778, 1940, 481 +}, +{ + 214, -46, 7870, 4406, -521 +}, +{ + -896, 4818, 8501, 1623, -887 +}, +{ + -696, 3178, 6480, -302, 1081 +}, +{ + 517, 599, 1002, 567, 560 +}, +{ + -2075, -834, 4712, -340, 896 +}, +{ + 1435, -644, 3993, -612, -2063 +} +}; + +const SKP_int16 SKP_Silk_LTP_gain_vq_1_Q14[ 20 ][ 5 ] = +{ +{ + 1655, 2918, 5001, 3010, 1775 +}, +{ + 113, 198, 856, 176, 178 +}, +{ + -843, 2479, 7858, 5371, 574 +}, +{ + 59, 5356, 7648, 2850, -315 +}, +{ + 3840, 4851, 6527, 1583, -1233 +}, +{ + 1620, 1760, 2330, 1876, 2045 +}, +{ + -545, 1854, 11792, 1547, -307 +}, +{ + -604, 689, 5369, 5074, 4265 +}, +{ + 521, -1331, 9829, 6209, -1211 +}, +{ + -1315, 6747, 9929, -1410, 546 +}, +{ + 117, -144, 2810, 1649, 5240 +}, +{ + 5392, 3476, 2425, -38, 633 +}, +{ + 14, -449, 5274, 3547, -171 +}, +{ + -98, 395, 9114, 1676, 844 +}, +{ + -908, 3843, 8861, -957, 1474 +}, +{ + 396, 6747, 5379, -329, 1269 +}, +{ + -335, 2830, 4281, 270, -54 +}, +{ + 1502, 5609, 8958, 6045, 2059 +}, +{ + -370, 479, 5267, 5726, 1174 +}, +{ + 5237, -1144, 6510, 455, 512 +} +}; + +const SKP_int16 SKP_Silk_LTP_gain_vq_2_Q14[ 40 ][ 5 ] = +{ +{ + -278, 415, 9345, 7106, -431 +}, +{ + -1006, 3863, 9524, 4724, -871 +}, +{ + -954, 4624, 11722, 973, -300 +}, +{ + -117, 7066, 8331, 1959, -901 +}, +{ + 593, 3412, 6070, 4914, 1567 +}, +{ + 54, -51, 12618, 4228, -844 +}, +{ + 3157, 4822, 5229, 2313, 717 +}, +{ + -244, 1161, 14198, 779, 69 +}, +{ + -1218, 5603, 12894, -2301, 1001 +}, +{ + -132, 3960, 9526, 577, 1806 +}, +{ + -1633, 8815, 10484, -2452, 895 +}, +{ + 235, 450, 1243, 667, 437 +}, +{ + 959, -2630, 10897, 8772, -1852 +}, +{ + 2420, 2046, 8893, 4427, -1569 +}, +{ + 23, 7091, 8356, -1285, 1508 +}, +{ + -1133, 835, 7662, 6043, 2800 +}, +{ + 439, 391, 11016, 2253, 1362 +}, +{ + -1020, 2876, 13436, 4015, -3020 +}, +{ + 1060, -2690, 13512, 5565, -1394 +}, +{ + -1420, 8007, 11421, -152, -1672 +}, +{ + -893, 2895, 15434, -1490, 159 +}, +{ + -1054, 428, 12208, 8538, -3344 +}, +{ + 1772, -1304, 7593, 6185, 561 +}, +{ + 525, -1207, 6659, 11151, -1170 +}, +{ + 439, 2667, 4743, 2359, 5515 +}, +{ + 2951, 7432, 7909, -230, -1564 +}, +{ + -72, 2140, 5477, 1391, 1580 +}, +{ + 476, -1312, 15912, 2174, -1027 +}, +{ + 5737, 441, 2493, 2043, 2757 +}, +{ + 228, -43, 1803, 6663, 7064 +}, +{ + 4596, 9182, 1917, -200, 203 +}, +{ + -704, 12039, 5451, -1188, 542 +}, +{ + 1782, -1040, 10078, 7513, -2767 +}, +{ + -2626, 7747, 9019, 62, 1710 +}, +{ + 235, -233, 2954, 10921, 1947 +}, +{ + 10854, 2814, 1232, -111, 222 +}, +{ + 2267, 2778, 12325, 156, -1658 +}, +{ + -2950, 8095, 16330, 268, -3626 +}, +{ + 67, 2083, 7950, -80, -2432 +}, +{ + 518, -66, 1718, 415, 11435 +} +}; + +const SKP_int16 * const SKP_Silk_LTP_vq_ptrs_Q14[ NB_LTP_CBKS ] = { + &SKP_Silk_LTP_gain_vq_0_Q14[ 0 ][ 0 ], + &SKP_Silk_LTP_gain_vq_1_Q14[ 0 ][ 0 ], + &SKP_Silk_LTP_gain_vq_2_Q14[ 0 ][ 0 ] +}; + +const SKP_int SKP_Silk_LTP_vq_sizes[ NB_LTP_CBKS ] = { + 10, 20, 40 +}; diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c new file mode 100644 index 0000000..d91bda3 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c @@ -0,0 +1,890 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.29 + 2.66 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB0_10.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ NLSF_MSVQ_CB0_10_VECTORS + NLSF_MSVQ_CB0_10_STAGES ] = +{ + 0, + 2658, + 4420, + 6107, + 7757, + 9408, + 10955, + 12502, + 13983, + 15432, + 16882, + 18331, + 19750, + 21108, + 22409, + 23709, + 25010, + 26256, + 27501, + 28747, + 29965, + 31158, + 32351, + 33544, + 34736, + 35904, + 36997, + 38091, + 39185, + 40232, + 41280, + 42327, + 43308, + 44290, + 45271, + 46232, + 47192, + 48132, + 49032, + 49913, + 50775, + 51618, + 52462, + 53287, + 54095, + 54885, + 55675, + 56449, + 57222, + 57979, + 58688, + 59382, + 60076, + 60726, + 61363, + 61946, + 62505, + 63052, + 63543, + 63983, + 64396, + 64766, + 65023, + 65279, + 65535, + 0, + 4977, + 9542, + 14106, + 18671, + 23041, + 27319, + 31596, + 35873, + 39969, + 43891, + 47813, + 51652, + 55490, + 59009, + 62307, + 65535, + 0, + 8571, + 17142, + 25529, + 33917, + 42124, + 49984, + 57844, + 65535, + 0, + 8732, + 17463, + 25825, + 34007, + 42189, + 50196, + 58032, + 65535, + 0, + 8948, + 17704, + 25733, + 33762, + 41791, + 49821, + 57678, + 65535, + 0, + 4374, + 8655, + 12936, + 17125, + 21313, + 25413, + 29512, + 33611, + 37710, + 41809, + 45820, + 49832, + 53843, + 57768, + 61694, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 65 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 82 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 91 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 100 ], + &SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ 109 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + 23, + 8, + 5, + 5, + 5, + 9 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ NLSF_MSVQ_CB0_10_VECTORS ] = +{ + 148, 167, + 169, 170, + 170, 173, + 173, 175, + 176, 176, + 176, 177, + 179, 181, + 181, 181, + 183, 183, + 183, 184, + 185, 185, + 185, 185, + 186, 189, + 189, 189, + 191, 191, + 191, 194, + 194, 194, + 195, 195, + 196, 198, + 199, 200, + 201, 201, + 202, 203, + 204, 204, + 205, 205, + 206, 209, + 210, 210, + 213, 214, + 218, 220, + 221, 226, + 231, 234, + 239, 256, + 256, 256, + 119, 123, + 123, 123, + 125, 126, + 126, 126, + 128, 130, + 130, 131, + 131, 135, + 138, 139, + 94, 94, + 95, 95, + 96, 98, + 98, 99, + 93, 93, + 95, 96, + 96, 97, + 98, 100, + 92, 93, + 97, 97, + 97, 97, + 98, 98, + 125, 126, + 126, 127, + 127, 128, + 128, 128, + 128, 128, + 129, 129, + 129, 130, + 130, 131 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_10_ndelta_min_Q15[ 10 + 1 ] = +{ + 563, + 3, + 22, + 20, + 3, + 3, + 132, + 119, + 358, + 86, + 964 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * NLSF_MSVQ_CB0_10_VECTORS ] = +{ + 2210, 4023, + 6981, 9260, + 12573, 15687, + 19207, 22383, + 25981, 29142, + 3285, 4172, + 6116, 10856, + 15289, 16826, + 19701, 22010, + 24721, 29313, + 1554, 2511, + 6577, 10337, + 13837, 16511, + 20086, 23214, + 26480, 29464, + 3062, 4017, + 5771, 10037, + 13365, 14952, + 20140, 22891, + 25229, 29603, + 2085, 3457, + 5934, 8718, + 11501, 13670, + 17997, 21817, + 24935, 28745, + 2776, 4093, + 6421, 10413, + 15111, 16806, + 20825, 23826, + 26308, 29411, + 2717, 4034, + 5697, 8463, + 14301, 16354, + 19007, 23413, + 25812, 28506, + 2872, 3702, + 5881, 11034, + 17141, 18879, + 21146, 23451, + 25817, 29600, + 2999, 4015, + 7357, 11219, + 12866, 17307, + 20081, 22644, + 26774, 29107, + 2942, 3866, + 5918, 11915, + 13909, 16072, + 20453, 22279, + 27310, 29826, + 2271, 3527, + 6606, 9729, + 12943, 17382, + 20224, 22345, + 24602, 28290, + 2207, 3310, + 5844, 9339, + 11141, 15651, + 18576, 21177, + 25551, 28228, + 3963, 4975, + 6901, 11588, + 13466, 15577, + 19231, 21368, + 25510, 27759, + 2749, 3549, + 6966, 13808, + 15653, 17645, + 20090, 22599, + 26467, 28537, + 2126, 3504, + 5109, 9954, + 12550, 14620, + 19703, 21687, + 26457, 29106, + 3966, 5745, + 7442, 9757, + 14468, 16404, + 19135, 23048, + 25375, 28391, + 3197, 4751, + 6451, 9298, + 13038, 14874, + 17962, 20627, + 23835, 28464, + 3195, 4081, + 6499, 12252, + 14289, 16040, + 18357, 20730, + 26980, 29309, + 1533, 2471, + 4486, 7796, + 12332, 15758, + 19567, 22298, + 25673, 29051, + 2002, 2971, + 4985, 8083, + 13181, 15435, + 18237, 21517, + 24595, 28351, + 3808, 4925, + 6710, 10201, + 12011, 14300, + 18457, 20391, + 26525, 28956, + 2281, 3418, + 4979, 8726, + 15964, 18104, + 20250, 22771, + 25286, 28954, + 3051, 5479, + 7290, 9848, + 12744, 14503, + 18665, 23684, + 26065, 28947, + 2364, 3565, + 5502, 9621, + 14922, 16621, + 19005, 20996, + 26310, 29302, + 4093, 5212, + 6833, 9880, + 16303, 18286, + 20571, 23614, + 26067, 29128, + 2941, 3996, + 6038, 10638, + 12668, 14451, + 16798, 19392, + 26051, 28517, + 3863, 5212, + 7019, 9468, + 11039, 13214, + 19942, 22344, + 25126, 29539, + 4615, 6172, + 7853, 10252, + 12611, 14445, + 19719, 22441, + 24922, 29341, + 3566, 4512, + 6985, 8684, + 10544, 16097, + 18058, 22475, + 26066, 28167, + 4481, 5489, + 7432, 11414, + 13191, 15225, + 20161, 22258, + 26484, 29716, + 3320, 4320, + 6621, 9867, + 11581, 14034, + 21168, 23210, + 26588, 29903, + 3794, 4689, + 6916, 8655, + 10143, 16144, + 19568, 21588, + 27557, 29593, + 2446, 3276, + 5918, 12643, + 16601, 18013, + 21126, 23175, + 27300, 29634, + 2450, 3522, + 5437, 8560, + 15285, 19911, + 21826, 24097, + 26567, 29078, + 2580, 3796, + 5580, 8338, + 9969, 12675, + 18907, 22753, + 25450, 29292, + 3325, 4312, + 6241, 7709, + 9164, 14452, + 21665, 23797, + 27096, 29857, + 3338, 4163, + 7738, 11114, + 12668, 14753, + 16931, 22736, + 25671, 28093, + 3840, 4755, + 7755, 13471, + 15338, 17180, + 20077, 22353, + 27181, 29743, + 2504, 4079, + 8351, 12118, + 15046, 18595, + 21684, 24704, + 27519, 29937, + 5234, 6342, + 8267, 11821, + 15155, 16760, + 20667, 23488, + 25949, 29307, + 2681, 3562, + 6028, 10827, + 18458, 20458, + 22303, 24701, + 26912, 29956, + 3374, 4528, + 6230, 8256, + 9513, 12730, + 18666, 20720, + 26007, 28425, + 2731, 3629, + 8320, 12450, + 14112, 16431, + 18548, 22098, + 25329, 27718, + 3481, 4401, + 7321, 9319, + 11062, 13093, + 15121, 22315, + 26331, 28740, + 3577, 4945, + 6669, 8792, + 10299, 12645, + 19505, 24766, + 26996, 29634, + 4058, 5060, + 7288, 10190, + 11724, 13936, + 15849, 18539, + 26701, 29845, + 4262, 5390, + 7057, 8982, + 10187, 15264, + 20480, 22340, + 25958, 28072, + 3404, 4329, + 6629, 7946, + 10121, 17165, + 19640, 22244, + 25062, 27472, + 3157, 4168, + 6195, 9319, + 10771, 13325, + 15416, 19816, + 24672, 27634, + 2503, 3473, + 5130, 6767, + 8571, 14902, + 19033, 21926, + 26065, 28728, + 4133, 5102, + 7553, 10054, + 11757, 14924, + 17435, 20186, + 23987, 26272, + 4972, 6139, + 7894, 9633, + 11320, 14295, + 21737, 24306, + 26919, 29907, + 2958, 3816, + 6851, 9204, + 10895, 18052, + 20791, 23338, + 27556, 29609, + 5234, 6028, + 8034, 10154, + 11242, 14789, + 18948, 20966, + 26585, 29127, + 5241, 6838, + 10526, 12819, + 14681, 17328, + 19928, 22336, + 26193, 28697, + 3412, 4251, + 5988, 7094, + 9907, 18243, + 21669, 23777, + 26969, 29087, + 2470, 3217, + 7797, 15296, + 17365, 19135, + 21979, 24256, + 27322, 29442, + 4939, 5804, + 8145, 11809, + 13873, 15598, + 17234, 19423, + 26476, 29645, + 5051, 6167, + 8223, 9655, + 12159, 17995, + 20464, 22832, + 26616, 28462, + 4987, 5907, + 9319, 11245, + 13132, 15024, + 17485, 22687, + 26011, 28273, + 5137, 6884, + 11025, 14950, + 17191, 19425, + 21807, 24393, + 26938, 29288, + 7057, 7884, + 9528, 10483, + 10960, 14811, + 19070, 21675, + 25645, 28019, + 6759, 7160, + 8546, 11779, + 12295, 13023, + 16627, 21099, + 24697, 28287, + 3863, 9762, + 11068, 11445, + 12049, 13960, + 18085, 21507, + 25224, 28997, + 397, 335, + 651, 1168, + 640, 765, + 465, 331, + 214, -194, + -578, -647, + -657, 750, + 564, 613, + 549, 630, + 304, -52, + 828, 922, + 443, 111, + 138, 124, + 169, 14, + 144, 83, + 132, 58, + -413, -752, + 869, 336, + 385, 69, + 56, 830, + -227, -266, + -368, -440, + -1195, 163, + 126, -228, + 802, 156, + 188, 120, + 376, 59, + -358, -558, + -1326, -254, + -202, -789, + 296, 92, + -70, -129, + -718, -1135, + 292, -29, + -631, 487, + -157, -153, + -279, 2, + -419, -342, + -34, -514, + -799, -1571, + -687, -609, + -546, -130, + -215, -252, + -446, -574, + -1337, 207, + -72, 32, + 103, -642, + 942, 733, + 187, 29, + -211, -814, + 143, 225, + 20, 24, + -268, -377, + 1623, 1133, + 667, 164, + 307, 366, + 187, 34, + 62, -313, + -832, -1482, + -1181, 483, + -42, -39, + -450, -1406, + -587, -52, + -760, 334, + 98, -60, + -500, -488, + -1058, 299, + 131, -250, + -251, -703, + 1037, 568, + -413, -265, + 1687, 573, + 345, 323, + 98, 61, + -102, 31, + 135, 149, + 617, 365, + -39, 34, + -611, 1201, + 1421, 736, + -414, -393, + -492, -343, + -316, -532, + 528, 172, + 90, 322, + -294, -319, + -541, 503, + 639, 401, + 1, -149, + -73, -167, + 150, 118, + 308, 218, + 121, 195, + -143, -261, + -1013, -802, + 387, 436, + 130, -427, + -448, -681, + 123, -87, + -251, -113, + 274, 310, + 445, 501, + 354, 272, + 141, -285, + 569, 656, + 37, -49, + 251, -386, + -263, 1122, + 604, 606, + 336, 95, + 34, 0, + 85, 180, + 207, -367, + -622, 1070, + -6, -79, + -160, -92, + -137, -276, + -323, -371, + -696, -1036, + 407, 102, + -86, -214, + -482, -647, + -28, -291, + -97, -180, + -250, -435, + -18, -76, + -332, 410, + 407, 168, + 539, 411, + 254, 111, + 58, -145, + 200, 30, + 187, 116, + 131, -367, + -475, 781, + -559, 561, + 195, -115, + 8, -168, + 30, 55, + -122, 131, + 82, -5, + -273, -50, + -632, 668, + 4, 32, + -26, -279, + 315, 165, + 197, 377, + 155, -41, + -138, -324, + -109, -617, + 360, 98, + -53, -319, + -114, -245, + -82, 507, + 468, 263, + -137, -389, + 652, 354, + -18, -227, + -462, -135, + 317, 53, + -16, 66, + -72, -126, + -356, -347, + -328, -72, + -337, 324, + 152, 349, + 169, -196, + 179, 254, + 260, 325, + -74, -80, + 75, -31, + 270, 275, + 87, 278, + -446, -301, + 309, 71, + -25, -242, + 516, 161, + -162, -83, + 329, 230, + -311, -259, + 177, -26, + -462, 89, + 257, 6, + -130, -93, + -456, -317, + -221, -206, + -417, -182, + -74, 234, + 48, 261, + 359, 231, + 258, 85, + -282, 252, + -147, -222, + 251, -207, + 443, 123, + -417, -36, + 273, -241, + 240, -112, + 44, -167, + 126, -124, + -77, 58, + -401, 333, + -118, 82, + 126, 151, + -433, 359, + -130, -102, + 131, -244, + 86, 85, + -462, 414, + -240, 16, + 145, 28, + -205, -481, + 373, 293, + -72, -174, + 62, 259, + -8, -18, + 362, 233, + 185, 43, + 278, 27, + 193, 570, + -248, 189, + 92, 31, + -275, -3, + 243, 176, + 438, 209, + 206, -51, + 79, 109, + 168, -185, + -308, -68, + -618, 385, + -310, -108, + -164, 165, + 61, -152, + -101, -412, + -268, -257, + -40, -20, + -28, -158, + -301, 271, + 380, -338, + -367, -132, + 64, 114, + -131, -225, + -156, -260, + -63, -116, + 155, -586, + -202, 254, + -287, 178, + 227, -106, + -294, 164, + 298, -100, + 185, 317, + 193, -45, + 28, 80, + -87, -433, + 22, -48, + 48, -237, + -229, -139, + 120, -364, + 268, -136, + 396, 125, + 130, -89, + -272, 118, + -256, -68, + -451, 488, + 143, -165, + -48, -190, + 106, 219, + 47, 435, + 245, 97, + 75, -418, + 121, -187, + 570, -200, + -351, 225, + -21, -217, + 234, -111, + 194, 14, + 242, 118, + 140, -397, + 355, 361, + -45, -195 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB0_10_Stage_info[ NLSF_MSVQ_CB0_10_STAGES ] = +{ + { 64, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 0 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 0 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 64 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 64 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 80 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 80 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 88 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 88 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 96 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 96 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_10_Q15[ 10 * 104 ], &SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5[ 104 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_10 = +{ + NLSF_MSVQ_CB0_10_STAGES, + SKP_Silk_NLSF_CB0_10_Stage_info, + SKP_Silk_NLSF_MSVQ_CB0_10_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h new file mode 100644 index 0000000..37e2906 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_TABLES_NLSF_CB0_10_H +#define SKP_SILK_TABLES_NLSF_CB0_10_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB0_10_STAGES 6 +#define NLSF_MSVQ_CB0_10_VECTORS 120 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_10_CDF[ NLSF_MSVQ_CB0_10_VECTORS + NLSF_MSVQ_CB0_10_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_10_CDF_start_ptr[ NLSF_MSVQ_CB0_10_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB0_10_CDF_middle_idx[ NLSF_MSVQ_CB0_10_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c new file mode 100644 index 0000000..cfa87c6 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c @@ -0,0 +1,1320 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.51 + 7.38 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB0_16.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ NLSF_MSVQ_CB0_16_VECTORS + NLSF_MSVQ_CB0_16_STAGES ] = +{ + 0, + 1449, + 2749, + 4022, + 5267, + 6434, + 7600, + 8647, + 9695, + 10742, + 11681, + 12601, + 13444, + 14251, + 15008, + 15764, + 16521, + 17261, + 18002, + 18710, + 19419, + 20128, + 20837, + 21531, + 22225, + 22919, + 23598, + 24277, + 24956, + 25620, + 26256, + 26865, + 27475, + 28071, + 28667, + 29263, + 29859, + 30443, + 31026, + 31597, + 32168, + 32727, + 33273, + 33808, + 34332, + 34855, + 35379, + 35902, + 36415, + 36927, + 37439, + 37941, + 38442, + 38932, + 39423, + 39914, + 40404, + 40884, + 41364, + 41844, + 42324, + 42805, + 43285, + 43754, + 44224, + 44694, + 45164, + 45623, + 46083, + 46543, + 46993, + 47443, + 47892, + 48333, + 48773, + 49213, + 49653, + 50084, + 50515, + 50946, + 51377, + 51798, + 52211, + 52614, + 53018, + 53422, + 53817, + 54212, + 54607, + 55002, + 55388, + 55775, + 56162, + 56548, + 56910, + 57273, + 57635, + 57997, + 58352, + 58698, + 59038, + 59370, + 59702, + 60014, + 60325, + 60630, + 60934, + 61239, + 61537, + 61822, + 62084, + 62346, + 62602, + 62837, + 63072, + 63302, + 63517, + 63732, + 63939, + 64145, + 64342, + 64528, + 64701, + 64867, + 65023, + 65151, + 65279, + 65407, + 65535, + 0, + 5099, + 9982, + 14760, + 19538, + 24213, + 28595, + 32976, + 36994, + 41012, + 44944, + 48791, + 52557, + 56009, + 59388, + 62694, + 65535, + 0, + 9955, + 19697, + 28825, + 36842, + 44686, + 52198, + 58939, + 65535, + 0, + 8949, + 17335, + 25720, + 33926, + 41957, + 49987, + 57845, + 65535, + 0, + 9724, + 18642, + 26998, + 35355, + 43532, + 51534, + 59365, + 65535, + 0, + 8750, + 17499, + 26249, + 34448, + 42471, + 50494, + 58178, + 65535, + 0, + 8730, + 17273, + 25816, + 34176, + 42536, + 50203, + 57869, + 65535, + 0, + 8769, + 17538, + 26307, + 34525, + 42742, + 50784, + 58319, + 65535, + 0, + 8736, + 17101, + 25466, + 33653, + 41839, + 50025, + 57864, + 65535, + 0, + 4368, + 8735, + 12918, + 17100, + 21283, + 25465, + 29558, + 33651, + 37744, + 41836, + 45929, + 50022, + 54027, + 57947, + 61782, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 129 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 146 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 155 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 164 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 173 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 182 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 191 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 200 ], + &SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ 209 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + 42, + 8, + 4, + 5, + 5, + 5, + 5, + 5, + 5, + 9 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ NLSF_MSVQ_CB0_16_VECTORS ] = +{ + 176, 181, + 182, 183, + 186, 186, + 191, 191, + 191, 196, + 197, 201, + 203, 206, + 206, 206, + 207, 207, + 209, 209, + 209, 209, + 210, 210, + 210, 211, + 211, 211, + 212, 214, + 216, 216, + 217, 217, + 217, 217, + 218, 218, + 219, 219, + 220, 221, + 222, 223, + 223, 223, + 223, 224, + 224, 224, + 225, 225, + 226, 226, + 226, 226, + 227, 227, + 227, 227, + 227, 227, + 228, 228, + 228, 228, + 229, 229, + 229, 230, + 230, 230, + 231, 231, + 231, 231, + 232, 232, + 232, 232, + 233, 234, + 235, 235, + 235, 236, + 236, 236, + 236, 237, + 237, 237, + 237, 240, + 240, 240, + 240, 241, + 242, 243, + 244, 244, + 247, 247, + 248, 248, + 248, 249, + 251, 255, + 255, 256, + 260, 260, + 261, 264, + 264, 266, + 266, 268, + 271, 274, + 276, 279, + 288, 288, + 288, 288, + 118, 120, + 121, 121, + 122, 125, + 125, 129, + 129, 130, + 131, 132, + 136, 137, + 138, 145, + 87, 88, + 91, 97, + 98, 100, + 105, 106, + 92, 95, + 95, 96, + 97, 97, + 98, 99, + 88, 92, + 95, 95, + 96, 97, + 98, 109, + 93, 93, + 93, 96, + 97, 97, + 99, 101, + 93, 94, + 94, 95, + 95, 99, + 99, 99, + 93, 93, + 93, 96, + 96, 97, + 100, 102, + 93, 95, + 95, 96, + 96, 96, + 98, 99, + 125, 125, + 127, 127, + 127, 127, + 128, 128, + 128, 128, + 128, 128, + 129, 130, + 131, 132 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB0_16_ndelta_min_Q15[ 16 + 1 ] = +{ + 266, + 3, + 40, + 3, + 3, + 16, + 78, + 89, + 107, + 141, + 188, + 146, + 272, + 240, + 235, + 215, + 632 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * NLSF_MSVQ_CB0_16_VECTORS ] = +{ + 1170, 2278, 3658, 5374, + 7666, 9113, 11298, 13304, + 15371, 17549, 19587, 21487, + 23798, 26038, 28318, 30201, + 1628, 2334, 4115, 6036, + 7818, 9544, 11777, 14021, + 15787, 17408, 19466, 21261, + 22886, 24565, 26714, 28059, + 1724, 2670, 4056, 6532, + 8357, 10119, 12093, 14061, + 16491, 18795, 20417, 22402, + 24251, 26224, 28410, 29956, + 1493, 3427, 4789, 6399, + 8435, 10168, 12000, 14066, + 16229, 18210, 20040, 22098, + 24153, 26095, 28183, 30121, + 1119, 2089, 4295, 6245, + 8691, 10741, 12688, 15057, + 17028, 18792, 20717, 22514, + 24497, 26548, 28619, 30630, + 1363, 2417, 3927, 5556, + 7422, 9315, 11879, 13767, + 16143, 18520, 20458, 22578, + 24539, 26436, 28318, 30318, + 1122, 2503, 5216, 7148, + 9310, 11078, 13175, 14800, + 16864, 18700, 20436, 22488, + 24572, 26602, 28555, 30426, + 600, 1317, 2970, 5609, + 7694, 9784, 12169, 14087, + 16379, 18378, 20551, 22686, + 24739, 26697, 28646, 30355, + 941, 1882, 4274, 5540, + 8482, 9858, 11940, 14287, + 16091, 18501, 20326, 22612, + 24711, 26638, 28814, 30430, + 635, 1699, 4376, 5948, + 8097, 10115, 12274, 14178, + 16111, 17813, 19695, 21773, + 23927, 25866, 28022, 30134, + 1408, 2222, 3524, 5615, + 7345, 8849, 10989, 12772, + 15352, 17026, 18919, 21062, + 23329, 25215, 27209, 29023, + 701, 1307, 3548, 6301, + 7744, 9574, 11227, 12978, + 15170, 17565, 19775, 22097, + 24230, 26335, 28377, 30231, + 1752, 2364, 4879, 6569, + 7813, 9796, 11199, 14290, + 15795, 18000, 20396, 22417, + 24308, 26124, 28360, 30633, + 901, 1629, 3356, 4635, + 7256, 8767, 9971, 11558, + 15215, 17544, 19523, 21852, + 23900, 25978, 28133, 30184, + 981, 1669, 3323, 4693, + 6213, 8692, 10614, 12956, + 15211, 17711, 19856, 22122, + 24344, 26592, 28723, 30481, + 1607, 2577, 4220, 5512, + 8532, 10388, 11627, 13671, + 15752, 17199, 19840, 21859, + 23494, 25786, 28091, 30131, + 811, 1471, 3144, 5041, + 7430, 9389, 11174, 13255, + 15157, 16741, 19583, 22167, + 24115, 26142, 28383, 30395, + 1543, 2144, 3629, 6347, + 7333, 9339, 10710, 13596, + 15099, 17340, 20102, 21886, + 23732, 25637, 27818, 29917, + 492, 1185, 2940, 5488, + 7095, 8751, 11596, 13579, + 16045, 18015, 20178, 22127, + 24265, 26406, 28484, 30357, + 1547, 2282, 3693, 6341, + 7758, 9607, 11848, 13236, + 16564, 18069, 19759, 21404, + 24110, 26606, 28786, 30655, + 685, 1338, 3409, 5262, + 6950, 9222, 11414, 14523, + 16337, 17893, 19436, 21298, + 23293, 25181, 27973, 30520, + 887, 1581, 3057, 4318, + 7192, 8617, 10047, 13106, + 16265, 17893, 20233, 22350, + 24379, 26384, 28314, 30189, + 2285, 3745, 5662, 7576, + 9323, 11320, 13239, 15191, + 17175, 19225, 21108, 22972, + 24821, 26655, 28561, 30460, + 1496, 2108, 3448, 6898, + 8328, 9656, 11252, 12823, + 14979, 16482, 18180, 20085, + 22962, 25160, 27705, 29629, + 575, 1261, 3861, 6627, + 8294, 10809, 12705, 14768, + 17076, 19047, 20978, 23055, + 24972, 26703, 28720, 30345, + 1682, 2213, 3882, 6238, + 7208, 9646, 10877, 13431, + 14805, 16213, 17941, 20873, + 23550, 25765, 27756, 29461, + 888, 1616, 3924, 5195, + 7206, 8647, 9842, 11473, + 16067, 18221, 20343, 22774, + 24503, 26412, 28054, 29731, + 805, 1454, 2683, 4472, + 7936, 9360, 11398, 14345, + 16205, 17832, 19453, 21646, + 23899, 25928, 28387, 30463, + 1640, 2383, 3484, 5082, + 6032, 8606, 11640, 12966, + 15842, 17368, 19346, 21182, + 23638, 25889, 28368, 30299, + 1632, 2204, 4510, 7580, + 8718, 10512, 11962, 14096, + 15640, 17194, 19143, 22247, + 24563, 26561, 28604, 30509, + 2043, 2612, 3985, 6851, + 8038, 9514, 10979, 12789, + 15426, 16728, 18899, 20277, + 22902, 26209, 28711, 30618, + 2224, 2798, 4465, 5320, + 7108, 9436, 10986, 13222, + 14599, 18317, 20141, 21843, + 23601, 25700, 28184, 30582, + 835, 1541, 4083, 5769, + 7386, 9399, 10971, 12456, + 15021, 18642, 20843, 23100, + 25292, 26966, 28952, 30422, + 1795, 2343, 4809, 5896, + 7178, 8545, 10223, 13370, + 14606, 16469, 18273, 20736, + 23645, 26257, 28224, 30390, + 1734, 2254, 4031, 5188, + 6506, 7872, 9651, 13025, + 14419, 17305, 19495, 22190, + 24403, 26302, 28195, 30177, + 1841, 2349, 3968, 4764, + 6376, 9825, 11048, 13345, + 14682, 16252, 18183, 21363, + 23918, 26156, 28031, 29935, + 1432, 2047, 5631, 6927, + 8198, 9675, 11358, 13506, + 14802, 16419, 18339, 22019, + 24124, 26177, 28130, 30586, + 1730, 2320, 3744, 4808, + 6007, 9666, 10997, 13622, + 15234, 17495, 20088, 22002, + 23603, 25400, 27379, 29254, + 1267, 1915, 5483, 6812, + 8229, 9919, 11589, 13337, + 14747, 17965, 20552, 22167, + 24519, 26819, 28883, 30642, + 1526, 2229, 4240, 7388, + 8953, 10450, 11899, 13718, + 16861, 18323, 20379, 22672, + 24797, 26906, 28906, 30622, + 2175, 2791, 4104, 6875, + 8612, 9798, 12152, 13536, + 15623, 17682, 19213, 21060, + 24382, 26760, 28633, 30248, + 454, 1231, 4339, 5738, + 7550, 9006, 10320, 13525, + 16005, 17849, 20071, 21992, + 23949, 26043, 28245, 30175, + 2250, 2791, 4230, 5283, + 6762, 10607, 11879, 13821, + 15797, 17264, 20029, 22266, + 24588, 26437, 28244, 30419, + 1696, 2216, 4308, 8385, + 9766, 11030, 12556, 14099, + 16322, 17640, 19166, 20590, + 23967, 26858, 28798, 30562, + 2452, 3236, 4369, 6118, + 7156, 9003, 11509, 12796, + 15749, 17291, 19491, 22241, + 24530, 26474, 28273, 30073, + 1811, 2541, 3555, 5480, + 9123, 10527, 11894, 13659, + 15262, 16899, 19366, 21069, + 22694, 24314, 27256, 29983, + 1553, 2246, 4559, 5500, + 6754, 7874, 11739, 13571, + 15188, 17879, 20281, 22510, + 24614, 26649, 28786, 30755, + 1982, 2768, 3834, 5964, + 8732, 9908, 11797, 14813, + 16311, 17946, 21097, 22851, + 24456, 26304, 28166, 29755, + 1824, 2529, 3817, 5449, + 6854, 8714, 10381, 12286, + 14194, 15774, 19524, 21374, + 23695, 26069, 28096, 30212, + 2212, 2854, 3947, 5898, + 9930, 11556, 12854, 14788, + 16328, 17700, 20321, 22098, + 23672, 25291, 26976, 28586, + 2023, 2599, 4024, 4916, + 6613, 11149, 12457, 14626, + 16320, 17822, 19673, 21172, + 23115, 26051, 28825, 30758, + 1628, 2206, 3467, 4364, + 8679, 10173, 11864, 13679, + 14998, 16938, 19207, 21364, + 23850, 26115, 28124, 30273, + 2014, 2603, 4114, 7254, + 8516, 10043, 11822, 13503, + 16329, 17826, 19697, 21280, + 23151, 24661, 26807, 30161, + 2376, 2980, 4422, 5770, + 7016, 9723, 11125, 13516, + 15485, 16985, 19160, 20587, + 24401, 27180, 29046, 30647, + 2454, 3502, 4624, 6019, + 7632, 8849, 10792, 13964, + 15523, 17085, 19611, 21238, + 22856, 25108, 28106, 29890, + 1573, 2274, 3308, 5999, + 8977, 10104, 12457, 14258, + 15749, 18180, 19974, 21253, + 23045, 25058, 27741, 30315, + 1943, 2730, 4140, 6160, + 7491, 8986, 11309, 12775, + 14820, 16558, 17909, 19757, + 21512, 23605, 27274, 29527, + 2021, 2582, 4494, 5835, + 6993, 8245, 9827, 14733, + 16462, 17894, 19647, 21083, + 23764, 26667, 29072, 30990, + 1052, 1775, 3218, 4378, + 7666, 9403, 11248, 13327, + 14972, 17962, 20758, 22354, + 25071, 27209, 29001, 30609, + 2218, 2866, 4223, 5352, + 6581, 9980, 11587, 13121, + 15193, 16583, 18386, 20080, + 22013, 25317, 28127, 29880, + 2146, 2840, 4397, 5840, + 7449, 8721, 10512, 11936, + 13595, 17253, 19310, 20891, + 23417, 25627, 27749, 30231, + 1972, 2619, 3756, 6367, + 7641, 8814, 12286, 13768, + 15309, 18036, 19557, 20904, + 22582, 24876, 27800, 30440, + 2005, 2577, 4272, 7373, + 8558, 10223, 11770, 13402, + 16502, 18000, 19645, 21104, + 22990, 26806, 29505, 30942, + 1153, 1822, 3724, 5443, + 6990, 8702, 10289, 11899, + 13856, 15315, 17601, 21064, + 23692, 26083, 28586, 30639, + 1304, 1869, 3318, 7195, + 9613, 10733, 12393, 13728, + 15822, 17474, 18882, 20692, + 23114, 25540, 27684, 29244, + 2093, 2691, 4018, 6658, + 7947, 9147, 10497, 11881, + 15888, 17821, 19333, 21233, + 23371, 25234, 27553, 29998, + 575, 1331, 5304, 6910, + 8425, 10086, 11577, 13498, + 16444, 18527, 20565, 22847, + 24914, 26692, 28759, 30157, + 1435, 2024, 3283, 4156, + 7611, 10592, 12049, 13927, + 15459, 18413, 20495, 22270, + 24222, 26093, 28065, 30099, + 1632, 2168, 5540, 7478, + 8630, 10391, 11644, 14321, + 15741, 17357, 18756, 20434, + 22799, 26060, 28542, 30696, + 1407, 2245, 3405, 5639, + 9419, 10685, 12104, 13495, + 15535, 18357, 19996, 21689, + 24351, 26550, 28853, 30564, + 1675, 2226, 4005, 8223, + 9975, 11155, 12822, 14316, + 16504, 18137, 19574, 21050, + 22759, 24912, 28296, 30634, + 1080, 1614, 3622, 7565, + 8748, 10303, 11713, 13848, + 15633, 17434, 19761, 21825, + 23571, 25393, 27406, 29063, + 1693, 2229, 3456, 4354, + 5670, 10890, 12563, 14167, + 15879, 17377, 19817, 21971, + 24094, 26131, 28298, 30099, + 2042, 2959, 4195, 5740, + 7106, 8267, 11126, 14973, + 16914, 18295, 20532, 21982, + 23711, 25769, 27609, 29351, + 984, 1612, 3808, 5265, + 6885, 8411, 9547, 10889, + 12522, 16520, 19549, 21639, + 23746, 26058, 28310, 30374, + 2036, 2538, 4166, 7761, + 9146, 10412, 12144, 13609, + 15588, 17169, 18559, 20113, + 21820, 24313, 28029, 30612, + 1871, 2355, 4061, 5143, + 7464, 10129, 11941, 15001, + 16680, 18354, 19957, 22279, + 24861, 26872, 28988, 30615, + 2566, 3161, 4643, 6227, + 7406, 9970, 11618, 13416, + 15889, 17364, 19121, 20817, + 22592, 24720, 28733, 31082, + 1700, 2327, 4828, 5939, + 7567, 9154, 11087, 12771, + 14209, 16121, 20222, 22671, + 24648, 26656, 28696, 30745, + 3169, 3873, 5046, 6868, + 8184, 9480, 12335, 14068, + 15774, 17971, 20231, 21711, + 23520, 25245, 27026, 28730, + 1564, 2391, 4229, 6730, + 8905, 10459, 13026, 15033, + 17265, 19809, 21849, 23741, + 25490, 27312, 29061, 30527, + 2864, 3559, 4719, 6441, + 9592, 11055, 12763, 14784, + 16428, 18164, 20486, 22262, + 24183, 26263, 28383, 30224, + 2673, 3449, 4581, 5983, + 6863, 8311, 12464, 13911, + 15738, 17791, 19416, 21182, + 24025, 26561, 28723, 30440, + 2419, 3049, 4274, 6384, + 8564, 9661, 11288, 12676, + 14447, 17578, 19816, 21231, + 23099, 25270, 26899, 28926, + 1278, 2001, 3000, 5353, + 9995, 11777, 13018, 14570, + 16050, 17762, 19982, 21617, + 23371, 25083, 27656, 30172, + 932, 1624, 2798, 4570, + 8592, 9988, 11552, 13050, + 16921, 18677, 20415, 22810, + 24817, 26819, 28804, 30385, + 2324, 2973, 4156, 5702, + 6919, 8806, 10259, 12503, + 15015, 16567, 19418, 21375, + 22943, 24550, 27024, 29849, + 1564, 2373, 3455, 4907, + 5975, 7436, 11786, 14505, + 16107, 18148, 20019, 21653, + 23740, 25814, 28578, 30372, + 3025, 3729, 4866, 6520, + 9487, 10943, 12358, 14258, + 16174, 17501, 19476, 21408, + 23227, 24906, 27347, 29407, + 1270, 1965, 6802, 7995, + 9204, 10828, 12507, 14230, + 15759, 17860, 20369, 22502, + 24633, 26514, 28535, 30525, + 2210, 2749, 4266, 7487, + 9878, 11018, 12823, 14431, + 16247, 18626, 20450, 22054, + 23739, 25291, 27074, 29169, + 1275, 1926, 4330, 6573, + 8441, 10920, 13260, 15008, + 16927, 18573, 20644, 22217, + 23983, 25474, 27372, 28645, + 3015, 3670, 5086, 6372, + 7888, 9309, 10966, 12642, + 14495, 16172, 18080, 19972, + 22454, 24899, 27362, 29975, + 2882, 3733, 5113, 6482, + 8125, 9685, 11598, 13288, + 15405, 17192, 20178, 22426, + 24801, 27014, 29212, 30811, + 2300, 2968, 4101, 5442, + 6327, 7910, 12455, 13862, + 15747, 17505, 19053, 20679, + 22615, 24658, 27499, 30065, + 2257, 2940, 4430, 5991, + 7042, 8364, 9414, 11224, + 15723, 17420, 19253, 21469, + 23915, 26053, 28430, 30384, + 1227, 2045, 3818, 5011, + 6990, 9231, 11024, 13011, + 17341, 19017, 20583, 22799, + 25195, 26876, 29351, 30805, + 1354, 1924, 3789, 8077, + 10453, 11639, 13352, 14817, + 16743, 18189, 20095, 22014, + 24593, 26677, 28647, 30256, + 3142, 4049, 6197, 7417, + 8753, 10156, 11533, 13181, + 15947, 17655, 19606, 21402, + 23487, 25659, 28123, 30304, + 1317, 2263, 4725, 7611, + 9667, 11634, 14143, 16258, + 18724, 20698, 22379, 24007, + 25775, 27251, 28930, 30593, + 1570, 2323, 3818, 6215, + 9893, 11556, 13070, 14631, + 16152, 18290, 21386, 23346, + 25114, 26923, 28712, 30168, + 2297, 3905, 6287, 8558, + 10668, 12766, 15019, 17102, + 19036, 20677, 22341, 23871, + 25478, 27085, 28851, 30520, + 1915, 2507, 4033, 5749, + 7059, 8871, 10659, 12198, + 13937, 15383, 16869, 18707, + 23175, 25818, 28514, 30501, + 2404, 2918, 5190, 6252, + 7426, 9887, 12387, 14795, + 16754, 18368, 20338, 22003, + 24236, 26456, 28490, 30397, + 1621, 2227, 3479, 5085, + 9425, 12892, 14246, 15652, + 17205, 18674, 20446, 22209, + 23778, 25867, 27931, 30093, + 1869, 2390, 4105, 7021, + 11221, 12775, 14059, 15590, + 17024, 18608, 20595, 22075, + 23649, 25154, 26914, 28671, + 2551, 3252, 4688, 6562, + 7869, 9125, 10475, 11800, + 15402, 18780, 20992, 22555, + 24289, 25968, 27465, 29232, + 2705, 3493, 4735, 6360, + 7905, 9352, 11538, 13430, + 15239, 16919, 18619, 20094, + 21800, 23342, 25200, 29257, + 2166, 2791, 4011, 5081, + 5896, 9038, 13407, 14703, + 16543, 18189, 19896, 21857, + 24872, 26971, 28955, 30514, + 1865, 3021, 4696, 6534, + 8343, 9914, 12789, 14103, + 16533, 17729, 21340, 22439, + 24873, 26330, 28428, 30154, + 3369, 4345, 6573, 8763, + 10309, 11713, 13367, 14784, + 16483, 18145, 19839, 21247, + 23292, 25477, 27555, 29447, + 1265, 2184, 5443, 7893, + 10591, 13139, 15105, 16639, + 18402, 19826, 21419, 22995, + 24719, 26437, 28363, 30125, + 1584, 2004, 3535, 4450, + 8662, 10764, 12832, 14978, + 16972, 18794, 20932, 22547, + 24636, 26521, 28701, 30567, + 3419, 4528, 6602, 7890, + 9508, 10875, 12771, 14357, + 16051, 18330, 20630, 22490, + 25070, 26936, 28946, 30542, + 1726, 2252, 4597, 6950, + 8379, 9823, 11363, 12794, + 14306, 15476, 16798, 18018, + 21671, 25550, 28148, 30367, + 3385, 3870, 5307, 6388, + 7141, 8684, 12695, 14939, + 16480, 18277, 20537, 22048, + 23947, 25965, 28214, 29956, + 2771, 3306, 4450, 5560, + 6453, 9493, 13548, 14754, + 16743, 18447, 20028, 21736, + 23746, 25353, 27141, 29066, + 3028, 3900, 6617, 7893, + 9211, 10480, 12047, 13583, + 15182, 16662, 18502, 20092, + 22190, 24358, 26302, 28957, + 2000, 2550, 4067, 6837, + 9628, 11002, 12594, 14098, + 15589, 17195, 18679, 20099, + 21530, 23085, 24641, 29022, + 2844, 3302, 5103, 6107, + 6911, 8598, 12416, 14054, + 16026, 18567, 20672, 22270, + 23952, 25771, 27658, 30026, + 4043, 5150, 7268, 9056, + 10916, 12638, 14543, 16184, + 17948, 19691, 21357, 22981, + 24825, 26591, 28479, 30233, + 2109, 2625, 4320, 5525, + 7454, 10220, 12980, 14698, + 17627, 19263, 20485, 22381, + 24279, 25777, 27847, 30458, + 1550, 2667, 6473, 9496, + 10985, 12352, 13795, 15233, + 17099, 18642, 20461, 22116, + 24197, 26291, 28403, 30132, + 2411, 3084, 4145, 5394, + 6367, 8154, 13125, 16049, + 17561, 19125, 21258, 22762, + 24459, 26317, 28255, 29702, + 4159, 4516, 5956, 7635, + 8254, 8980, 11208, 14133, + 16210, 17875, 20196, 21864, + 23840, 25747, 28058, 30012, + 2026, 2431, 2845, 3618, + 7950, 9802, 12721, 14460, + 16576, 18984, 21376, 23319, + 24961, 26718, 28971, 30640, + 3429, 3833, 4472, 4912, + 7723, 10386, 12981, 15322, + 16699, 18807, 20778, 22551, + 24627, 26494, 28334, 30482, + 4740, 5169, 5796, 6485, + 6998, 8830, 11777, 14414, + 16831, 18413, 20789, 22369, + 24236, 25835, 27807, 30021, + 150, 168, -17, -107, + -142, -229, -320, -406, + -503, -620, -867, -935, + -902, -680, -398, -114, + -398, -355, 49, 255, + 114, 260, 399, 264, + 317, 431, 514, 531, + 435, 356, 238, 106, + -43, -36, -169, -224, + -391, -633, -776, -970, + -844, -455, -181, -12, + 85, 85, 164, 195, + 122, 85, -158, -640, + -903, 9, 7, -124, + 149, 32, 220, 369, + 242, 115, 79, 84, + -146, -216, -70, 1024, + 751, 574, 440, 377, + 352, 203, 30, 16, + -3, 81, 161, 100, + -148, -176, 933, 750, + 404, 171, -2, -146, + -411, -442, -541, -552, + -442, -269, -240, -52, + 603, 635, 405, 178, + 215, 19, -153, -167, + -290, -219, 151, 271, + 151, 119, 303, 266, + 100, 69, -293, -657, + 939, 659, 442, 351, + 132, 98, -16, -1, + -135, -200, -223, -89, + 167, 154, 172, 237, + -45, -183, -228, -486, + 263, 608, 158, -125, + -390, -227, -118, 43, + -457, -392, -769, -840, + 20, -117, -194, -189, + -173, -173, -33, 32, + 174, 144, 115, 167, + 57, 44, 14, 147, + 96, -54, -142, -129, + -254, -331, 304, 310, + -52, -419, -846, -1060, + -88, -123, -202, -343, + -554, -961, -951, 327, + 159, 81, 255, 227, + 120, 203, 256, 192, + 164, 224, 290, 195, + 216, 209, 128, 832, + 1028, 889, 698, 504, + 408, 355, 218, 32, + -115, -84, -276, -100, + -312, -484, 899, 682, + 465, 456, 241, -12, + -275, -425, -461, -367, + -33, -28, -102, -194, + -527, 863, 906, 463, + 245, 13, -212, -305, + -105, 163, 279, 176, + 93, 67, 115, 192, + 61, -50, -132, -175, + -224, -271, -629, -252, + 1158, 972, 638, 280, + 300, 326, 143, -152, + -214, -287, 53, -42, + -236, -352, -423, -248, + -129, -163, -178, -119, + 85, 57, 514, 382, + 374, 402, 424, 423, + 271, 197, 97, 40, + 39, -97, -191, -164, + -230, -256, -410, 396, + 327, 127, 10, -119, + -167, -291, -274, -141, + -99, -226, -218, -139, + -224, -209, -268, -442, + -413, 222, 58, 521, + 344, 258, 76, -42, + -142, -165, -123, -92, + 47, 8, -3, -191, + -11, -164, -167, -351, + -740, 311, 538, 291, + 184, 29, -105, 9, + -30, -54, -17, -77, + -271, -412, -622, -648, + 476, 186, -66, -197, + -73, -94, -15, 47, + 28, 112, -58, -33, + 65, 19, 84, 86, + 276, 114, 472, 786, + 799, 625, 415, 178, + -35, -26, 5, 9, + 83, 39, 37, 39, + -184, -374, -265, -362, + -501, 337, 716, 478, + -60, -125, -163, 362, + 17, -122, -233, 279, + 138, 157, 318, 193, + 189, 209, 266, 252, + -46, -56, -277, -429, + 464, 386, 142, 44, + -43, 66, 264, 182, + 47, 14, -26, -79, + 49, 15, -128, -203, + -400, -478, 325, 27, + 234, 411, 205, 129, + 12, 58, 123, 57, + 171, 137, 96, 128, + -32, 134, -12, 57, + 119, 26, -22, -165, + -500, -701, -528, -116, + 64, -8, 97, -9, + -162, -66, -156, -194, + -303, -546, -341, 546, + 358, 95, 45, 76, + 270, 403, 205, 100, + 123, 50, -53, -144, + -110, -13, 32, -228, + -130, 353, 296, 56, + -372, -253, 365, 73, + 10, -34, -139, -191, + -96, 5, 44, -85, + -179, -129, -192, -246, + -85, -110, -155, -44, + -27, 145, 138, 79, + 32, -148, -577, -634, + 191, 94, -9, -35, + -77, -84, -56, -171, + -298, -271, -243, -156, + -328, -235, -76, -128, + -121, 129, 13, -22, + 32, 45, -248, -65, + 193, -81, 299, 57, + -147, 192, -165, -354, + -334, -106, -156, -40, + -3, -68, 124, -257, + 78, 124, 170, 412, + 227, 105, -104, 12, + 154, 250, 274, 258, + 4, -27, 235, 152, + 51, 338, 300, 7, + -314, -411, 215, 170, + -9, -93, -77, 76, + 67, 54, 200, 315, + 163, 72, -91, -402, + 158, 187, -156, -91, + 290, 267, 167, 91, + 140, 171, 112, 9, + -42, -177, -440, 385, + 80, 15, 172, 129, + 41, -129, -372, -24, + -75, -30, -170, 10, + -118, 57, 78, -101, + 232, 161, 123, 256, + 277, 101, -192, -629, + -100, -60, -232, 66, + 13, -13, -80, -239, + 239, 37, 32, 89, + -319, -579, 450, 360, + 3, -29, -299, -89, + -54, -110, -246, -164, + 6, -188, 338, 176, + -92, 197, 137, 134, + 12, -2, 56, -183, + 114, -36, -131, -204, + 75, -25, -174, 191, + -15, -290, -429, -267, + 79, 37, 106, 23, + -384, 425, 70, -14, + 212, 105, 15, -2, + -42, -37, -123, 108, + 28, -48, 193, 197, + 173, -33, 37, 73, + -57, 256, 137, -58, + -430, -228, 217, -51, + -10, -58, -6, 22, + 104, 61, -119, 169, + 144, 16, -46, -394, + 60, 454, -80, -298, + -65, 25, 0, -24, + -65, -417, 465, 276, + -3, -194, -13, 130, + 19, -6, -21, -24, + -180, -53, -85, 20, + 118, 147, 113, -75, + -289, 226, -122, 227, + 270, 125, 109, 197, + 125, 138, 44, 60, + 25, -55, -167, -32, + -139, -193, -173, -316, + 287, -208, 253, 239, + 27, -80, -188, -28, + -182, -235, 156, -117, + 128, -48, -58, -226, + 172, 181, 167, 19, + 62, 10, 2, 181, + 151, 108, -16, -11, + -78, -331, 411, 133, + 17, 104, 64, -184, + 24, -30, -3, -283, + 121, 204, -8, -199, + -21, -80, -169, -157, + -191, -136, 81, 155, + 14, -131, 244, 74, + -57, -47, -280, 347, + 111, -77, -128, -142, + -194, -125, -6, -68, + 91, 1, 23, 14, + -154, -34, 23, -38, + -343, 503, 146, -38, + -46, -41, 58, 31, + 63, -48, -117, 45, + 28, 1, -89, -5, + -44, -29, -448, 487, + 204, 81, 46, -106, + -302, 380, 120, -38, + -12, -39, 70, -3, + 25, -65, 30, -11, + 34, -15, 22, -115, + 0, -79, -83, 45, + 114, 43, 150, 36, + 233, 149, 195, 5, + 25, -52, -475, 274, + 28, -39, -8, -66, + -255, 258, 56, 143, + -45, -190, 165, -60, + 20, 2, 125, -129, + 51, -8, -335, 288, + 38, 59, 25, -42, + 23, -118, -112, 11, + -55, -133, -109, 24, + -105, 78, -64, -245, + 202, -65, -127, 162, + 40, -94, 89, -85, + -119, -103, 97, 9, + -70, -28, 194, 86, + -112, -92, -114, 74, + -49, 46, -84, -178, + 113, 52, -205, 333, + 88, 222, 56, -55, + 13, 86, 4, -77, + 224, 114, -105, 112, + 125, -29, -18, -144, + 22, -58, -99, 28, + 114, -66, -32, -169, + -314, 285, 72, -74, + 179, 28, -79, -182, + 13, -55, 147, 13, + 12, -54, 31, -84, + -17, -75, -228, 83, + -375, 436, 110, -63, + -27, -136, 169, -56, + -8, -171, 184, -42, + 148, 68, 204, 235, + 110, -229, 91, 171, + -43, -3, -26, -99, + -111, 71, -170, 202, + -67, 181, -37, 109, + -120, 3, -55, -260, + -16, 152, 91, 142, + 42, 44, 134, 47, + 17, -35, 22, 79, + -169, 41, 46, 277, + -93, -49, -126, 37, + -103, -34, -22, -90, + -134, -205, 92, -9, + 1, -195, -239, 45, + 54, 18, -23, -1, + -80, -98, -20, -261, + 306, 72, 20, -89, + -217, 11, 6, -82, + 89, 13, -129, -89, + 83, -71, -55, 130, + -98, -146, -27, -57, + 53, 275, 17, 170, + -5, -54, 132, -64, + 72, 160, -125, -168, + 72, 40, 170, 78, + 248, 116, 20, 84, + 31, -34, 190, 38, + 13, -106, 225, 27, + -168, 24, -157, -122, + 165, 11, -161, -213, + -12, -51, -101, 42, + 101, 27, 55, 111, + 75, 71, -96, -1, + 65, -277, 393, -26, + -44, -68, -84, -66, + -95, 235, 179, -25, + -41, 27, -91, -128, + -222, 146, -72, -30, + -24, 55, -126, -68, + -58, -127, 13, -97, + -106, 174, -100, 155, + 101, -146, -21, 261, + 22, 38, -66, 65, + 4, 70, 64, 144, + 59, 213, 71, -337, + 303, -52, 51, -56, + 1, 10, -15, -5, + 34, 52, 228, 131, + 161, -127, -214, 238, + 123, 64, -147, -50, + -34, -127, 204, 162, + 85, 41, 5, -140, + 73, -150, 56, -96, + -66, -20, 2, -235, + 59, -22, -107, 150, + -16, -47, -4, 81, + -67, 167, 149, 149, + -157, 288, -156, -27, + -8, 18, 83, -24, + -41, -167, 158, -100, + 93, 53, 201, 15, + 42, 266, 278, -12, + -6, -37, 85, 6, + 20, -188, -271, 107, + -13, -80, 51, 202, + 173, -69, 78, -188, + 46, 4, 153, 12, + -138, 169, 5, -58, + -123, -108, -243, 150, + 10, -191, 246, -15, + 38, 25, -10, 14, + 61, 50, -206, -215, + -220, 90, 5, -149, + -219, 56, 142, 24, + -376, 77, -80, 75, + 6, 42, -101, 16, + 56, 14, -57, 3, + -17, 80, 57, -36, + 88, -59, -97, -19, + -148, 46, -219, 226, + 114, -4, -72, -15, + 37, -49, -28, 247, + 44, 123, 47, -122, + -38, 17, 4, -113, + -32, -224, 154, -134, + 196, 71, -267, -85, + 28, -70, 89, -120, + 99, -2, 64, 76, + -166, -48, 189, -35, + -92, -169, -123, 339, + 38, -25, 38, -35, + 225, -139, -50, -63, + 246, 60, -185, -109, + -49, -53, -167, 51, + 149, 60, -101, -33, + 25, -76, 120, 32, + -30, -83, 102, 91, + -186, -261, 131, -197 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB0_16_Stage_info[ NLSF_MSVQ_CB0_16_STAGES ] = +{ + { 128, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 0 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 0 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 128 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 128 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 144 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 144 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 152 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 152 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 160 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 160 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 168 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 168 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 176 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 176 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 184 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 184 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 192 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 192 ] }, + { 16, &SKP_Silk_NLSF_MSVQ_CB0_16_Q15[ 16 * 200 ], &SKP_Silk_NLSF_MSVQ_CB0_16_rates_Q5[ 200 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB0_16 = +{ + NLSF_MSVQ_CB0_16_STAGES, + SKP_Silk_NLSF_CB0_16_Stage_info, + SKP_Silk_NLSF_MSVQ_CB0_16_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h new file mode 100644 index 0000000..bf110e5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_TABLES_NLSF_CB0_16_H +#define SKP_SILK_TABLES_NLSF_CB0_16_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB0_16_STAGES 10 +#define NLSF_MSVQ_CB0_16_VECTORS 216 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB0_16_CDF[ NLSF_MSVQ_CB0_16_VECTORS + NLSF_MSVQ_CB0_16_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB0_16_CDF_start_ptr[ NLSF_MSVQ_CB0_16_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB0_16_CDF_middle_idx[ NLSF_MSVQ_CB0_16_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c new file mode 100644 index 0000000..46b3543 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c @@ -0,0 +1,578 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.19 + 1.61 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB1_10.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ NLSF_MSVQ_CB1_10_VECTORS + NLSF_MSVQ_CB1_10_STAGES ] = +{ + 0, + 17096, + 24130, + 28997, + 33179, + 36696, + 40213, + 42493, + 44252, + 45973, + 47551, + 49095, + 50542, + 51898, + 53196, + 54495, + 55685, + 56851, + 57749, + 58628, + 59435, + 60207, + 60741, + 61220, + 61700, + 62179, + 62659, + 63138, + 63617, + 64097, + 64576, + 65056, + 65535, + 0, + 20378, + 33032, + 40395, + 46721, + 51707, + 56585, + 61157, + 65535, + 0, + 15055, + 25472, + 35447, + 42501, + 48969, + 54773, + 60212, + 65535, + 0, + 12069, + 22440, + 32812, + 40145, + 46870, + 53595, + 59630, + 65535, + 0, + 10839, + 19954, + 27957, + 35961, + 43965, + 51465, + 58805, + 65535, + 0, + 8933, + 17674, + 26415, + 34785, + 42977, + 50820, + 58496, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 33 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 42 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 51 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 60 ], + &SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ 69 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + 5, + 3, + 4, + 4, + 5, + 5 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ NLSF_MSVQ_CB1_10_VECTORS ] = +{ + 62, 103, + 120, 127, + 135, 135, + 155, 167, + 168, 172, + 173, 176, + 179, 181, + 181, 185, + 186, 198, + 199, 203, + 205, 222, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 54, 76, + 101, 108, + 119, 120, + 123, 125, + 68, 85, + 87, 103, + 107, 112, + 115, 116, + 78, 85, + 85, 101, + 105, 105, + 110, 111, + 83, 91, + 97, 97, + 97, 100, + 101, 105, + 92, 93, + 93, 95, + 96, 98, + 99, 103 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_10_ndelta_min_Q15[ 10 + 1 ] = +{ + 462, + 3, + 64, + 74, + 98, + 50, + 97, + 68, + 120, + 53, + 639 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * NLSF_MSVQ_CB1_10_VECTORS ] = +{ + 1877, 4646, + 7712, 10745, + 13964, 17028, + 20239, 23182, + 26471, 29287, + 1612, 3278, + 7086, 9975, + 13228, 16264, + 19596, 22690, + 26037, 28965, + 2169, 3830, + 6460, 8958, + 11960, 14750, + 18408, 21659, + 25018, 28043, + 3680, 6024, + 8986, 12256, + 15201, 18188, + 21741, 24460, + 27484, 30059, + 2584, 5187, + 7799, 10902, + 13179, 15765, + 19017, 22431, + 25891, 28698, + 3731, 5751, + 8650, 11742, + 15090, 17407, + 20391, 23421, + 26228, 29247, + 2107, 6323, + 8915, 12226, + 14775, 17791, + 20664, 23679, + 26829, 29353, + 1677, 2870, + 5386, 8077, + 11817, 15176, + 18657, 22006, + 25513, 28689, + 2111, 3625, + 7027, 10588, + 14059, 17193, + 21137, 24260, + 27577, 30036, + 2428, 4010, + 5765, 9376, + 13805, 15821, + 19444, 22389, + 25295, 29310, + 2256, 4628, + 8377, 12441, + 15283, 19462, + 22257, 25551, + 28432, 30304, + 2352, 3675, + 6129, 11868, + 14551, 16655, + 19624, 21883, + 26526, 28849, + 5243, 7248, + 10558, 13269, + 15651, 17919, + 21141, 23827, + 27102, 29519, + 4422, 6725, + 10449, 13273, + 16124, 19921, + 22826, 26061, + 28763, 30583, + 4508, 6291, + 9504, 11809, + 13827, 15950, + 19077, 22084, + 25740, 28658, + 2540, 4297, + 8579, 13578, + 16634, 19101, + 21547, 23887, + 26777, 29146, + 3377, 6358, + 10224, 14518, + 17905, 21056, + 23637, 25784, + 28161, 30109, + 4177, 5942, + 8159, 10108, + 12130, 15470, + 20191, 23326, + 26782, 29359, + 2492, 3801, + 6144, 9825, + 16000, 18671, + 20893, 23663, + 25899, 28974, + 3011, 4727, + 6834, 10505, + 12465, 14496, + 17065, 20052, + 25265, 28057, + 4149, 7197, + 12338, 15076, + 18002, 20190, + 22187, 24723, + 27083, 29125, + 2975, 4578, + 6448, 8378, + 9671, 13225, + 19502, 22277, + 26058, 28850, + 4102, 5760, + 7744, 9484, + 10744, 12308, + 14677, 19607, + 24841, 28381, + 4931, 9287, + 12477, 13395, + 13712, 14351, + 16048, 19867, + 24188, 28994, + 4141, 7867, + 13140, 17720, + 20064, 21108, + 21692, 22722, + 23736, 27449, + 4011, 8720, + 13234, 16206, + 17601, 18289, + 18524, 19689, + 23234, 27882, + 3420, 5995, + 11230, 15117, + 15907, 16783, + 17762, 23347, + 26898, 29946, + 3080, 6786, + 10465, 13676, + 18059, 23615, + 27058, 29082, + 29563, 29905, + 3038, 5620, + 9266, 12870, + 18803, 19610, + 20010, 20802, + 23882, 29306, + 3314, 6420, + 9046, 13262, + 15869, 23117, + 23667, 24215, + 24487, 25915, + 3469, 6963, + 10103, 15282, + 20531, 23240, + 25024, 26021, + 26736, 27255, + 3041, 6459, + 9777, 12896, + 16315, 19410, + 24070, 29353, + 31795, 32075, + -200, -134, + -113, -204, + -347, -440, + -352, -211, + -418, -172, + -313, 59, + 495, 772, + 721, 614, + 334, 444, + 225, 242, + 161, 16, + 274, 564, + -73, -188, + -395, -171, + 777, 508, + 1340, 1145, + 699, 196, + 223, 173, + 90, 25, + -26, 18, + 133, -105, + -360, -277, + 859, 634, + 41, -557, + -768, -926, + -601, -1021, + -1189, -365, + 225, 107, + 374, -50, + 433, 417, + 156, 39, + -597, -1397, + -1594, -592, + -485, -292, + 253, 87, + -0, -6, + -25, -345, + -240, 120, + 1261, 946, + 166, -277, + 241, 167, + 170, 429, + 518, 714, + 602, 254, + 134, 92, + -152, -324, + -394, 49, + -151, -304, + -724, -657, + -162, -369, + -35, 3, + -2, -312, + -200, -92, + -227, 242, + 628, 565, + -124, 1056, + 770, 101, + -84, -33, + 4, -192, + -272, 5, + -627, -977, + 419, 472, + 53, -103, + 145, 322, + -95, -31, + -100, -303, + -560, -1067, + -413, 714, + 283, 2, + -223, -367, + 523, 360, + -38, -115, + 378, -591, + -718, 448, + -481, -274, + 180, -88, + -581, -157, + -696, -1265, + 394, -479, + -23, 124, + -43, 19, + -113, -236, + -412, -659, + -200, 2, + -69, -342, + 199, 55, + 58, -36, + -51, -62, + 507, 507, + 427, 442, + 36, 601, + -141, 68, + 274, 274, + 68, -12, + -4, 71, + -193, -464, + -425, -383, + 408, 203, + -337, 236, + 410, -59, + -25, -341, + -449, 28, + -9, 90, + 332, -14, + -905, 96, + -540, -242, + 679, -59, + 192, -24, + 60, -217, + 5, -37, + 179, -20, + 311, 519, + 274, 72, + -326, -1030, + -262, 213, + 380, 82, + 328, 411, + -540, 574, + -283, 151, + 181, -402, + -278, -240, + -110, -227, + -264, -89, + -250, -259, + -27, 106, + -239, -98, + -390, 118, + 61, 104, + 294, 532, + 92, -13, + 60, -233, + 335, 541, + 307, -26, + -110, -91, + -231, -460, + 170, 201, + 96, -372, + 132, 435, + -302, 216, + -279, -41, + 74, 190, + 368, 273, + -186, -608, + -157, 159, + 12, 278, + 245, 307, + 25, -187, + -16, 55, + 30, -163, + 548, -307, + 106, -5, + 27, 330, + -416, 475, + 438, -235, + 104, 137, + 21, -5, + -300, -468, + 521, -347, + 170, -200, + -219, 308, + -122, -133, + 219, -16, + 359, 412, + -89, -111, + 48, 322, + 142, 177, + -286, -127, + -39, -63, + -42, -451, + 160, 308, + -57, 193, + -48, 74, + -346, 59, + -27, 27, + -469, -277, + -344, 282, + 262, 122, + 171, -249, + 27, 258, + 188, -3, + 67, -206, + -284, 291, + -117, -88, + -477, 375, + 50, 106, + 99, -182, + 438, -376, + -401, -49, + 119, -23, + -10, -48, + -116, -200, + -310, 121, + 73, 7, + 237, -226, + 139, -456, + 397, 35, + 3, -108, + 323, -75, + 332, 198, + -99, -21 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB1_10_Stage_info[ NLSF_MSVQ_CB1_10_STAGES ] = +{ + { 32, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 0 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 0 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 32 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 32 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 40 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 40 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 48 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 48 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 56 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 56 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_10_Q15[ 10 * 64 ], &SKP_Silk_NLSF_MSVQ_CB1_10_rates_Q5[ 64 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB1_10 = +{ + NLSF_MSVQ_CB1_10_STAGES, + SKP_Silk_NLSF_CB1_10_Stage_info, + SKP_Silk_NLSF_MSVQ_CB1_10_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h new file mode 100644 index 0000000..22fddf1 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_TABLES_NLSF_CB1_10_H +#define SKP_SILK_TABLES_NLSF_CB1_10_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB1_10_STAGES 6 +#define NLSF_MSVQ_CB1_10_VECTORS 72 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_10_CDF[ NLSF_MSVQ_CB1_10_VECTORS + NLSF_MSVQ_CB1_10_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_10_CDF_start_ptr[ NLSF_MSVQ_CB1_10_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB1_10_CDF_middle_idx[ NLSF_MSVQ_CB1_10_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c new file mode 100644 index 0000000..e68aedc --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c @@ -0,0 +1,704 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/**********************************************/ +/* This file has been automatically generated */ +/* */ +/* ROM usage: 0.29 + 3.57 kB */ +/**********************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_tables_NLSF_CB1_16.h" +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ NLSF_MSVQ_CB1_16_VECTORS + NLSF_MSVQ_CB1_16_STAGES ] = +{ + 0, + 19099, + 26957, + 30639, + 34242, + 37546, + 40447, + 43287, + 46005, + 48445, + 49865, + 51284, + 52673, + 53975, + 55221, + 56441, + 57267, + 58025, + 58648, + 59232, + 59768, + 60248, + 60729, + 61210, + 61690, + 62171, + 62651, + 63132, + 63613, + 64093, + 64574, + 65054, + 65535, + 0, + 28808, + 38775, + 46801, + 51785, + 55886, + 59410, + 62572, + 65535, + 0, + 27376, + 38639, + 45052, + 51465, + 55448, + 59021, + 62594, + 65535, + 0, + 33403, + 39569, + 45102, + 49961, + 54047, + 57959, + 61788, + 65535, + 0, + 25851, + 43356, + 47828, + 52204, + 55964, + 59413, + 62507, + 65535, + 0, + 34277, + 40337, + 45432, + 50311, + 54326, + 58171, + 61853, + 65535, + 0, + 33538, + 39865, + 45302, + 50076, + 54549, + 58478, + 62159, + 65535, + 0, + 27445, + 35258, + 40665, + 46072, + 51362, + 56540, + 61086, + 65535, + 0, + 22080, + 30779, + 37065, + 43085, + 48849, + 54613, + 60133, + 65535, + 0, + 13417, + 21748, + 30078, + 38231, + 46383, + 53091, + 59515, + 65535 +}; + +const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 0 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 33 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 42 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 51 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 60 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 69 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 78 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 87 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 96 ], + &SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ 105 ] +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + 5, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 4 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ NLSF_MSVQ_CB1_16_VECTORS ] = +{ + 57, 98, + 133, 134, + 138, 144, + 145, 147, + 152, 177, + 177, 178, + 181, 183, + 184, 202, + 206, 215, + 218, 222, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 227, 227, + 38, 87, + 97, 119, + 128, 135, + 140, 143, + 40, 81, + 107, 107, + 129, 134, + 134, 143, + 31, 109, + 114, 120, + 128, 130, + 131, 132, + 43, 61, + 124, 125, + 132, 136, + 141, 142, + 30, 110, + 118, 120, + 129, 131, + 133, 133, + 31, 108, + 115, 121, + 124, 130, + 133, 137, + 40, 98, + 115, 115, + 116, 117, + 123, 124, + 50, 93, + 108, 110, + 112, 112, + 114, 115, + 73, 95, + 95, 96, + 96, 105, + 107, 110 +}; + +const SKP_int SKP_Silk_NLSF_MSVQ_CB1_16_ndelta_min_Q15[ 16 + 1 ] = +{ + 148, + 3, + 60, + 68, + 117, + 86, + 121, + 124, + 152, + 153, + 207, + 151, + 225, + 239, + 126, + 183, + 792 +}; + +const SKP_int16 SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * NLSF_MSVQ_CB1_16_VECTORS ] = +{ + 1309, 3060, 5071, 6996, + 9028, 10938, 12934, 14891, + 16933, 18854, 20792, 22764, + 24753, 26659, 28626, 30501, + 1264, 2745, 4610, 6408, + 8286, 10043, 12084, 14108, + 16118, 18163, 20095, 22164, + 24264, 26316, 28329, 30251, + 1044, 2080, 3672, 5179, + 7140, 9100, 11070, 13065, + 15423, 17790, 19931, 22101, + 24290, 26361, 28499, 30418, + 1131, 2476, 4478, 6149, + 7902, 9875, 11938, 13809, + 15869, 17730, 19948, 21707, + 23761, 25535, 27426, 28917, + 1040, 2004, 4026, 6100, + 8432, 10494, 12610, 14694, + 16797, 18775, 20799, 22782, + 24772, 26682, 28631, 30516, + 2310, 3812, 5913, 7933, + 10033, 11881, 13885, 15798, + 17751, 19576, 21482, 23276, + 25157, 27010, 28833, 30623, + 1254, 2847, 5013, 6781, + 8626, 10370, 12726, 14633, + 16281, 17852, 19870, 21472, + 23002, 24629, 26710, 27960, + 1468, 3059, 4987, 7026, + 8741, 10412, 12281, 14020, + 15970, 17723, 19640, 21522, + 23472, 25661, 27986, 30225, + 2171, 3566, 5605, 7384, + 9404, 11220, 13030, 14758, + 16687, 18417, 20346, 22091, + 24055, 26212, 28356, 30397, + 2409, 4676, 7543, 9786, + 11419, 12935, 14368, 15653, + 17366, 18943, 20762, 22477, + 24440, 26327, 28284, 30242, + 2354, 4222, 6820, 9107, + 11596, 13934, 15973, 17682, + 19158, 20517, 21991, 23420, + 25178, 26936, 28794, 30527, + 1323, 2414, 4184, 6039, + 7534, 9398, 11099, 13097, + 14799, 16451, 18434, 20887, + 23490, 25838, 28046, 30225, + 1361, 3243, 6048, 8511, + 11001, 13145, 15073, 16608, + 18126, 19381, 20912, 22607, + 24660, 26668, 28663, 30566, + 1216, 2648, 5901, 8422, + 10037, 11425, 12973, 14603, + 16686, 18600, 20555, 22415, + 24450, 26280, 28206, 30077, + 2417, 4048, 6316, 8433, + 10510, 12757, 15072, 17295, + 19573, 21503, 23329, 24782, + 26235, 27689, 29214, 30819, + 1012, 2345, 4991, 7377, + 9465, 11916, 14296, 16566, + 18672, 20544, 22292, 23838, + 25415, 27050, 28848, 30551, + 1937, 3693, 6267, 8019, + 10372, 12194, 14287, 15657, + 17431, 18864, 20769, 22206, + 24037, 25463, 27383, 28602, + 1969, 3305, 5017, 6726, + 8375, 9993, 11634, 13280, + 15078, 16751, 18464, 20119, + 21959, 23858, 26224, 29298, + 1198, 2647, 5428, 7423, + 9775, 12155, 14665, 16344, + 18121, 19790, 21557, 22847, + 24484, 25742, 27639, 28711, + 1636, 3353, 5447, 7597, + 9837, 11647, 13964, 16019, + 17862, 20116, 22319, 24037, + 25966, 28086, 29914, 31294, + 2676, 4105, 6378, 8223, + 10058, 11549, 13072, 14453, + 15956, 17355, 18931, 20402, + 22183, 23884, 25717, 27723, + 1373, 2593, 4449, 5633, + 7300, 8425, 9474, 10818, + 12769, 15722, 19002, 21429, + 23682, 25924, 28135, 30333, + 1596, 3183, 5378, 7164, + 8670, 10105, 11470, 12834, + 13991, 15042, 16642, 17903, + 20759, 25283, 27770, 30240, + 2037, 3987, 6237, 8117, + 9954, 12245, 14217, 15892, + 17775, 20114, 22314, 25942, + 26305, 26483, 26796, 28561, + 2181, 3858, 5760, 7924, + 10041, 11577, 13769, 15700, + 17429, 19879, 23583, 24538, + 25212, 25693, 28688, 30507, + 1992, 3882, 6474, 7883, + 9381, 12672, 14340, 15701, + 16658, 17832, 20850, 22885, + 24677, 26457, 28491, 30460, + 2391, 3988, 5448, 7432, + 11014, 12579, 13140, 14146, + 15898, 18592, 21104, 22993, + 24673, 27186, 28142, 29612, + 1713, 5102, 6989, 7798, + 8670, 10110, 12746, 14881, + 16709, 18407, 20126, 22107, + 24181, 26198, 28237, 30137, + 1612, 3617, 6148, 8359, + 9576, 11528, 14936, 17809, + 18287, 18729, 19001, 21111, + 24631, 26596, 28740, 30643, + 2266, 4168, 7862, 9546, + 9618, 9703, 10134, 13897, + 16265, 18432, 20587, 22605, + 24754, 26994, 29125, 30840, + 1840, 3917, 6272, 7809, + 9714, 11438, 13767, 15799, + 19244, 21972, 22980, 23180, + 23723, 25650, 29117, 31085, + 1458, 3612, 6008, 7488, + 9827, 11893, 14086, 15734, + 17440, 19535, 22424, 24767, + 29246, 29928, 30516, 30947, + -102, -121, -31, -6, + 5, -2, 8, -18, + -4, 6, 14, -2, + -12, -16, -12, -60, + -126, -353, -574, -677, + -657, -617, -498, -393, + -348, -277, -225, -164, + -102, -70, -31, 33, + 4, 379, 387, 551, + 605, 620, 532, 482, + 442, 454, 385, 347, + 322, 299, 266, 200, + 1168, 951, 672, 246, + 60, -161, -259, -234, + -253, -282, -203, -187, + -155, -176, -198, -178, + 10, 170, 393, 609, + 555, 208, -330, -571, + -769, -633, -319, -43, + 95, 105, 106, 116, + -152, -140, -125, 5, + 173, 274, 264, 331, + -37, -293, -609, -786, + -959, -814, -645, -238, + -91, 36, -11, -101, + -279, -227, -40, 90, + 530, 677, 890, 1104, + 999, 835, 564, 295, + -280, -364, -340, -331, + -284, 288, 761, 880, + 988, 627, 146, -226, + -203, -181, -142, 39, + 24, -26, -107, -92, + -161, -135, -131, -88, + -160, -156, -75, -43, + -36, -6, -33, 33, + -324, -415, -108, 124, + 157, 191, 203, 197, + 144, 109, 152, 176, + 190, 122, 101, 159, + 663, 668, 480, 400, + 379, 444, 446, 458, + 343, 351, 310, 228, + 133, 44, 75, 63, + -84, 39, -29, 35, + -94, -233, -261, -354, + 77, 262, -24, -145, + -333, -409, -404, -597, + -488, -300, 910, 592, + 412, 120, 130, -51, + -37, -77, -172, -181, + -159, -148, -72, -62, + 510, 516, 113, -585, + -1075, -957, -417, -195, + 9, 7, -88, -173, + -91, 54, 98, 95, + -28, 197, -527, -621, + 157, 122, -168, 147, + 309, 300, 336, 315, + 396, 408, 376, 106, + -162, -170, -315, 98, + 821, 908, 570, -33, + -312, -568, -572, -378, + -107, 23, 156, 93, + -129, -87, 20, -72, + -37, 40, 21, 27, + 48, 75, 77, 65, + 46, 71, 66, 47, + 136, 344, 236, 322, + 170, 283, 269, 291, + 162, -43, -204, -259, + -240, -305, -350, -312, + 447, 348, 345, 257, + 71, -131, -77, -190, + -202, -40, 35, 133, + 261, 365, 438, 303, + -8, 22, 140, 137, + -300, -641, -764, -268, + -23, -25, 73, -162, + -150, -212, -72, 6, + 39, 78, 104, -93, + -308, -136, 117, -71, + -513, -820, -700, -450, + -161, -23, 29, 78, + 337, 106, -406, -782, + -112, 233, 383, 62, + -126, 6, -77, -29, + -146, -123, -51, -27, + -27, -381, -641, 402, + 539, 8, -207, -366, + -36, -27, -204, -227, + -237, -189, -64, 51, + -92, -137, -281, 62, + 233, 92, 148, 294, + 363, 416, 564, 625, + 370, -36, -469, -462, + 102, 168, 32, 117, + -21, 97, 139, 89, + 104, 35, 4, 82, + 66, 58, 73, 93, + -76, -320, -236, -189, + -203, -142, -27, -73, + 9, -9, -25, 12, + -15, 4, 4, -50, + 314, 180, 162, -49, + 199, -108, -227, -66, + -447, -67, -264, -394, + 5, 55, -133, -176, + -116, -241, 272, 109, + 282, 262, 192, -64, + -392, -514, 156, 203, + 154, 72, -34, -160, + -73, 3, -33, -431, + 321, 18, -567, -590, + -108, 88, 66, 51, + -31, -193, -46, 65, + -29, -23, 215, -31, + 101, -113, 32, 304, + 88, 320, 448, 5, + -439, -562, -508, -135, + -13, -171, -8, 182, + -99, -181, -149, 376, + 476, 64, -396, -652, + -150, 176, 222, 65, + -590, 719, 271, 399, + 245, 72, -156, -152, + -176, 59, 94, 125, + -9, -7, 9, 1, + -61, -116, -82, 1, + 79, 22, -44, -15, + -48, -65, -62, -101, + -102, -54, -70, -78, + -80, -25, 398, 71, + 139, 38, 90, 194, + 222, 249, 165, 94, + 221, 262, 163, 91, + -206, 573, 200, -287, + -147, 5, -18, -85, + -74, -125, -87, 85, + 141, 4, -4, 28, + 234, 48, -150, -111, + -506, 237, -209, 345, + 94, -124, 77, 121, + 143, 12, -80, -48, + 191, 144, -93, -65, + -151, -643, 435, 106, + 87, 7, 65, 102, + 94, 68, 5, 99, + 222, 93, 94, 355, + -13, -89, -228, -503, + 287, 109, 108, 449, + 253, -29, -109, -116, + 15, -73, -20, 131, + -147, 72, 59, -150, + -594, 273, 316, 132, + 199, 106, 198, 212, + 220, 82, 45, -13, + 223, 137, 270, 38, + 252, 135, -177, -207, + -360, -102, 403, 406, + -14, 83, 64, 51, + -7, -99, -97, -88, + -124, -65, 42, 32, + 28, 29, 12, 20, + 119, -26, -212, -201, + 373, 251, 141, 103, + 36, -52, 66, 18, + -6, -95, -196, 5, + 98, -85, -108, 218, + -164, 20, 356, 172, + 37, 266, 23, 112, + -24, -99, -92, -178, + 29, -278, 388, -60, + -220, 300, -13, 154, + 191, 15, -37, -110, + -153, -150, -114, -7, + -94, -31, -62, -177, + 4, -70, 35, 453, + 147, -247, -328, 101, + 20, -114, 147, 108, + -119, -109, -102, -238, + 55, -102, 173, -89, + 129, 138, -330, -160, + 485, 154, -59, -170, + -20, -34, -261, -40, + -129, 77, -84, 69, + 83, 160, 169, 63, + -516, 30, 336, 52, + -0, -52, -124, 158, + 19, 197, -10, -375, + 405, 285, 114, -395, + -47, 196, 62, 87, + -106, -65, -75, -69, + -13, 34, 99, 59, + 83, 98, 44, 0, + 24, 18, 17, 70, + -22, 194, 208, 144, + -79, -15, 32, -104, + -28, -105, -186, -212, + -228, -79, -76, 51, + -71, 72, 118, -34, + -3, -171, 5, 2, + -108, -125, 62, -58, + 58, -121, 73, -466, + 92, 63, -94, -78, + -76, 212, 36, -225, + -71, -354, 152, 143, + -79, -246, -51, -31, + -6, -270, 240, 210, + 30, -157, -231, 74, + -146, 88, -273, 156, + 92, 56, 71, 2, + 318, 164, 32, -110, + -35, -41, -95, -106, + 11, 132, -68, 55, + 123, -83, -149, 212, + 132, 0, -194, 55, + 206, -108, -353, 289, + -195, 1, 233, -22, + -60, 20, 26, 68, + 166, 27, -58, 130, + 112, 107, 27, -165, + 115, -93, -37, 38, + 83, 483, 65, -229, + -13, 157, 85, 50, + 136, 10, 32, 83, + 82, 55, 5, -9, + -52, -78, -81, -51, + 40, 18, -127, -224, + -41, 53, -210, -113, + 24, -17, -187, -89, + 8, 121, 83, 77, + 91, -74, -35, -112, + -161, -173, 102, 132, + -125, -61, 103, -260, + 52, 166, -32, -156, + -87, -56, 60, -70, + -124, 242, 114, -251, + -166, 201, 127, 28, + -11, 23, -80, -115, + -20, -51, -348, 340, + -34, 133, 13, 92, + -124, -136, -120, -26, + -6, 17, 28, 21, + 120, -168, 160, -35, + 115, 28, 9, 7, + -56, 39, 156, 256, + -18, 1, 277, 82, + -70, -144, -88, -13, + -59, -157, 8, -134, + 21, -40, 58, -21, + 194, -276, 97, 279, + -56, -140, 125, 57, + -184, -204, -70, -2, + 128, -202, -78, 230, + -23, 161, -102, 1, + 1, 180, -31, -86, + -167, -57, -60, 27, + -13, 99, 108, 111, + 76, 69, 34, -21, + 53, 38, 34, 78, + 73, 219, 51, 15, + -72, -103, -207, 30, + 213, -14, 31, -94, + -40, -144, 67, 4, + 105, 59, -240, 25, + 244, 69, 58, 23, + -24, -5, -15, -133, + -71, -67, 181, 29, + -45, 121, 96, 51, + -72, -53, 56, -153, + -27, 85, 183, 211, + 105, -34, -46, 43, + -72, -93, 36, -128, + 29, 111, -95, -156, + -179, -235, 21, -39, + -71, -33, -61, -252, + 230, -131, 157, -21, + -85, -28, -123, 80, + -160, 63, 47, -6, + -49, -96, -19, 17, + -58, 17, -0, -13, + -170, 25, -35, 59, + 10, -31, -413, 81, + 62, 18, -164, 245, + 92, -165, 42, 26, + 126, -248, 193, -55, + 16, 39, 14, 50 +}; + +const SKP_Silk_NLSF_CBS SKP_Silk_NLSF_CB1_16_Stage_info[ NLSF_MSVQ_CB1_16_STAGES ] = +{ + { 32, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 0 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 0 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 32 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 32 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 40 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 40 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 48 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 48 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 56 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 56 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 64 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 64 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 72 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 72 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 80 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 80 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 88 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 88 ] }, + { 8, &SKP_Silk_NLSF_MSVQ_CB1_16_Q15[ 16 * 96 ], &SKP_Silk_NLSF_MSVQ_CB1_16_rates_Q5[ 96 ] } +}; + +const SKP_Silk_NLSF_CB_struct SKP_Silk_NLSF_CB1_16 = +{ + NLSF_MSVQ_CB1_16_STAGES, + SKP_Silk_NLSF_CB1_16_Stage_info, + SKP_Silk_NLSF_MSVQ_CB1_16_ndelta_min_Q15, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr, + SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h new file mode 100644 index 0000000..ca63a44 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_TABLES_NLSF_CB1_16_H +#define SKP_SILK_TABLES_NLSF_CB1_16_H + +#include "SKP_Silk_define.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define NLSF_MSVQ_CB1_16_STAGES 10 +#define NLSF_MSVQ_CB1_16_VECTORS 104 + +/* NLSF codebook entropy coding tables */ +extern const SKP_uint16 SKP_Silk_NLSF_MSVQ_CB1_16_CDF[ NLSF_MSVQ_CB1_16_VECTORS + NLSF_MSVQ_CB1_16_STAGES ]; +extern const SKP_uint16 * const SKP_Silk_NLSF_MSVQ_CB1_16_CDF_start_ptr[ NLSF_MSVQ_CB1_16_STAGES ]; +extern const SKP_int SKP_Silk_NLSF_MSVQ_CB1_16_CDF_middle_idx[ NLSF_MSVQ_CB1_16_STAGES ]; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_tables_gain.c b/pkg/silk/csilk/SKP_Silk_tables_gain.c new file mode 100644 index 0000000..7556123 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_gain.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const SKP_uint16 SKP_Silk_gain_CDF[ 2 ][ 65 ] = +{ +{ + 0, 18, 45, 94, 181, 320, 519, 777, + 1093, 1468, 1909, 2417, 2997, 3657, 4404, 5245, + 6185, 7228, 8384, 9664, 11069, 12596, 14244, 16022, + 17937, 19979, 22121, 24345, 26646, 29021, 31454, 33927, + 36438, 38982, 41538, 44068, 46532, 48904, 51160, 53265, + 55184, 56904, 58422, 59739, 60858, 61793, 62568, 63210, + 63738, 64165, 64504, 64769, 64976, 65133, 65249, 65330, + 65386, 65424, 65451, 65471, 65487, 65501, 65513, 65524, + 65535 +}, +{ + 0, 214, 581, 1261, 2376, 3920, 5742, 7632, + 9449, 11157, 12780, 14352, 15897, 17427, 18949, 20462, + 21957, 23430, 24889, 26342, 27780, 29191, 30575, 31952, + 33345, 34763, 36200, 37642, 39083, 40519, 41930, 43291, + 44602, 45885, 47154, 48402, 49619, 50805, 51959, 53069, + 54127, 55140, 56128, 57101, 58056, 58979, 59859, 60692, + 61468, 62177, 62812, 63368, 63845, 64242, 64563, 64818, + 65023, 65184, 65306, 65391, 65447, 65482, 65505, 65521, + 65535 +} +}; + +const SKP_int SKP_Silk_gain_CDF_offset = 32; + + +const SKP_uint16 SKP_Silk_delta_gain_CDF[ 46 ] = { + 0, 2358, 3856, 7023, 15376, 53058, 59135, 61555, + 62784, 63498, 63949, 64265, 64478, 64647, 64783, 64894, + 64986, 65052, 65113, 65169, 65213, 65252, 65284, 65314, + 65338, 65359, 65377, 65392, 65403, 65415, 65424, 65432, + 65440, 65448, 65455, 65462, 65470, 65477, 65484, 65491, + 65499, 65506, 65513, 65521, 65528, 65535 +}; + +const SKP_int SKP_Silk_delta_gain_CDF_offset = 5; + +#ifdef __cplusplus +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_tables_other.c b/pkg/silk/csilk/SKP_Silk_tables_other.c new file mode 100644 index 0000000..27bba2b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_other.c @@ -0,0 +1,148 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_structs.h" +#include "SKP_Silk_define.h" +#include "SKP_Silk_tables.h" +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +const SKP_int32 TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = { + 0, 8000, 9000, 11000, 13000, 16000, 22000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = { + 0, 10000, 12000, 14000, 17000, 21000, 28000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = { + 0, 11000, 14000, 17000, 21000, 26000, 36000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 TargetRate_table_SWB[ TARGET_RATE_TAB_SZ ] = { + 0, 13000, 16000, 19000, 25000, 32000, 46000, MAX_TARGET_RATE_BPS +}; +const SKP_int32 SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = { + 19, 31, 35, 39, 43, 47, 54, 64 +}; + +const SKP_int32 SNR_table_one_bit_per_sample_Q7[ 4 ] = { + 1984, 2240, 2408, 2708 +}; + +/* Filter coeficicnts for HP filter: 4. Order filter implementad as two biquad filters */ +const SKP_int16 SKP_Silk_SWB_detect_B_HP_Q13[ NB_SOS ][ 3 ] = { + //{400, -550, 400}, {400, 130, 400}, {400, 390, 400} + {575, -948, 575}, {575, -221, 575}, {575, 104, 575} +}; +const SKP_int16 SKP_Silk_SWB_detect_A_HP_Q13[ NB_SOS ][ 2 ] = { + {14613, 6868}, {12883, 7337}, {11586, 7911} + //{14880, 6900}, {14400, 7300}, {13700, 7800} +}; + +/* Decoder high-pass filter coefficients for 24 kHz sampling, -6 dB @ 44 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_24[ DEC_HP_ORDER ] = {-16220, 8030}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_24[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* Decoder high-pass filter coefficients for 16 kHz sampling, - 6 dB @ 46 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_16[ DEC_HP_ORDER ] = {-16127, 7940}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_16[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* Decoder high-pass filter coefficients for 12 kHz sampling, -6 dB @ 44 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_12[ DEC_HP_ORDER ] = {-16043, 7859}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_12[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* Decoder high-pass filter coefficients for 8 kHz sampling, -6 dB @ 43 Hz */ +const SKP_int16 SKP_Silk_Dec_A_HP_8[ DEC_HP_ORDER ] = {-15885, 7710}; // second order AR coefs, Q13 +const SKP_int16 SKP_Silk_Dec_B_HP_8[ DEC_HP_ORDER + 1 ] = {8000, -16000, 8000}; // second order MA coefs, Q13 + +/* table for LSB coding */ +const SKP_uint16 SKP_Silk_lsb_CDF[ 3 ] = {0, 40000, 65535}; + +/* tables for LTPScale */ +const SKP_uint16 SKP_Silk_LTPscale_CDF[ 4 ] = {0, 32000, 48000, 65535}; +const SKP_int SKP_Silk_LTPscale_offset = 2; + +/* tables for VAD flag */ +const SKP_uint16 SKP_Silk_vadflag_CDF[ 3 ] = {0, 22000, 65535}; // 66% for speech, 33% for no speech +const SKP_int SKP_Silk_vadflag_offset = 1; + +/* tables for sampling rate */ +const SKP_int SKP_Silk_SamplingRates_table[ 4 ] = {8, 12, 16, 24}; +const SKP_uint16 SKP_Silk_SamplingRates_CDF[ 5 ] = {0, 16000, 32000, 48000, 65535}; +const SKP_int SKP_Silk_SamplingRates_offset = 2; + +/* tables for NLSF interpolation factor */ +const SKP_uint16 SKP_Silk_NLSF_interpolation_factor_CDF[ 6 ] = {0, 3706, 8703, 19226, 30926, 65535}; +const SKP_int SKP_Silk_NLSF_interpolation_factor_offset = 4; + +/* Table for frame termination indication */ +const SKP_uint16 SKP_Silk_FrameTermination_CDF[ 5 ] = {0, 20000, 45000, 56000, 65535}; +const SKP_int SKP_Silk_FrameTermination_offset = 2; + +/* Table for random seed */ +const SKP_uint16 SKP_Silk_Seed_CDF[ 5 ] = {0, 16384, 32768, 49152, 65535}; +const SKP_int SKP_Silk_Seed_offset = 2; + +/* Quantization offsets */ +const SKP_int16 SKP_Silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_VL_Q10, OFFSET_VH_Q10 }, { OFFSET_UVL_Q10, OFFSET_UVH_Q10 } +}; + +/* Table for LTPScale */ +const SKP_int16 SKP_Silk_LTPScales_table_Q14[ 3 ] = { 15565, 11469, 8192 }; + +#if SWITCH_TRANSITION_FILTERING +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const SKP_int32 SKP_Silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const SKP_int32 SKP_Silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c b/pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c new file mode 100644 index 0000000..555bc67 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c @@ -0,0 +1,199 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_pitch_lag_NB_CDF[ 8 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 194, 395, 608, 841, 1099, 1391, 1724, + 2105, 2544, 3047, 3624, 4282, 5027, 5865, 6799, + 7833, 8965, 10193, 11510, 12910, 14379, 15905, 17473, + 19065, 20664, 22252, 23814, 25335, 26802, 28206, 29541, + 30803, 31992, 33110, 34163, 35156, 36098, 36997, 37861, + 38698, 39515, 40319, 41115, 41906, 42696, 43485, 44273, + 45061, 45847, 46630, 47406, 48175, 48933, 49679, 50411, + 51126, 51824, 52502, 53161, 53799, 54416, 55011, 55584, + 56136, 56666, 57174, 57661, 58126, 58570, 58993, 59394, + 59775, 60134, 60472, 60790, 61087, 61363, 61620, 61856, + 62075, 62275, 62458, 62625, 62778, 62918, 63045, 63162, + 63269, 63368, 63459, 63544, 63623, 63698, 63769, 63836, + 63901, 63963, 64023, 64081, 64138, 64194, 64248, 64301, + 64354, 64406, 64457, 64508, 64558, 64608, 64657, 64706, + 64754, 64803, 64851, 64899, 64946, 64994, 65041, 65088, + 65135, 65181, 65227, 65272, 65317, 65361, 65405, 65449, + 65492, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_NB_CDF_offset = 43; + +const SKP_uint16 SKP_Silk_pitch_contour_NB_CDF[ 12 ] = { + 0, 14445, 18587, 25628, 30013, 34859, 40597, 48426, + 54460, 59033, 62990, 65535 +}; + +const SKP_int SKP_Silk_pitch_contour_NB_CDF_offset = 5; + +const SKP_uint16 SKP_Silk_pitch_lag_MB_CDF[ 12 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 132, 266, 402, 542, 686, 838, 997, + 1167, 1349, 1546, 1760, 1993, 2248, 2528, 2835, + 3173, 3544, 3951, 4397, 4882, 5411, 5984, 6604, + 7270, 7984, 8745, 9552, 10405, 11300, 12235, 13206, + 14209, 15239, 16289, 17355, 18430, 19507, 20579, 21642, + 22688, 23712, 24710, 25677, 26610, 27507, 28366, 29188, + 29971, 30717, 31427, 32104, 32751, 33370, 33964, 34537, + 35091, 35630, 36157, 36675, 37186, 37692, 38195, 38697, + 39199, 39701, 40206, 40713, 41222, 41733, 42247, 42761, + 43277, 43793, 44309, 44824, 45336, 45845, 46351, 46851, + 47347, 47836, 48319, 48795, 49264, 49724, 50177, 50621, + 51057, 51484, 51902, 52312, 52714, 53106, 53490, 53866, + 54233, 54592, 54942, 55284, 55618, 55944, 56261, 56571, + 56873, 57167, 57453, 57731, 58001, 58263, 58516, 58762, + 58998, 59226, 59446, 59656, 59857, 60050, 60233, 60408, + 60574, 60732, 60882, 61024, 61159, 61288, 61410, 61526, + 61636, 61742, 61843, 61940, 62033, 62123, 62210, 62293, + 62374, 62452, 62528, 62602, 62674, 62744, 62812, 62879, + 62945, 63009, 63072, 63135, 63196, 63256, 63316, 63375, + 63434, 63491, 63549, 63605, 63661, 63717, 63772, 63827, + 63881, 63935, 63988, 64041, 64094, 64147, 64199, 64252, + 64304, 64356, 64409, 64461, 64513, 64565, 64617, 64669, + 64721, 64773, 64824, 64875, 64925, 64975, 65024, 65072, + 65121, 65168, 65215, 65262, 65308, 65354, 65399, 65445, + 65490, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_MB_CDF_offset = 64; + +const SKP_uint16 SKP_Silk_pitch_lag_WB_CDF[ 16 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 106, 213, 321, 429, 539, 651, 766, + 884, 1005, 1132, 1264, 1403, 1549, 1705, 1870, + 2047, 2236, 2439, 2658, 2893, 3147, 3420, 3714, + 4030, 4370, 4736, 5127, 5546, 5993, 6470, 6978, + 7516, 8086, 8687, 9320, 9985, 10680, 11405, 12158, + 12938, 13744, 14572, 15420, 16286, 17166, 18057, 18955, + 19857, 20759, 21657, 22547, 23427, 24293, 25141, 25969, + 26774, 27555, 28310, 29037, 29736, 30406, 31048, 31662, + 32248, 32808, 33343, 33855, 34345, 34815, 35268, 35704, + 36127, 36537, 36938, 37330, 37715, 38095, 38471, 38844, + 39216, 39588, 39959, 40332, 40707, 41084, 41463, 41844, + 42229, 42615, 43005, 43397, 43791, 44186, 44583, 44982, + 45381, 45780, 46179, 46578, 46975, 47371, 47765, 48156, + 48545, 48930, 49312, 49690, 50064, 50433, 50798, 51158, + 51513, 51862, 52206, 52544, 52877, 53204, 53526, 53842, + 54152, 54457, 54756, 55050, 55338, 55621, 55898, 56170, + 56436, 56697, 56953, 57204, 57449, 57689, 57924, 58154, + 58378, 58598, 58812, 59022, 59226, 59426, 59620, 59810, + 59994, 60173, 60348, 60517, 60681, 60840, 60993, 61141, + 61284, 61421, 61553, 61679, 61800, 61916, 62026, 62131, + 62231, 62326, 62417, 62503, 62585, 62663, 62737, 62807, + 62874, 62938, 62999, 63057, 63113, 63166, 63217, 63266, + 63314, 63359, 63404, 63446, 63488, 63528, 63567, 63605, + 63642, 63678, 63713, 63748, 63781, 63815, 63847, 63879, + 63911, 63942, 63973, 64003, 64033, 64063, 64092, 64121, + 64150, 64179, 64207, 64235, 64263, 64291, 64319, 64347, + 64374, 64401, 64428, 64455, 64481, 64508, 64534, 64560, + 64585, 64610, 64635, 64660, 64685, 64710, 64734, 64758, + 64782, 64807, 64831, 64855, 64878, 64902, 64926, 64950, + 64974, 64998, 65022, 65045, 65069, 65093, 65116, 65139, + 65163, 65186, 65209, 65231, 65254, 65276, 65299, 65321, + 65343, 65364, 65386, 65408, 65429, 65450, 65471, 65493, + 65514, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_WB_CDF_offset = 86; + + +const SKP_uint16 SKP_Silk_pitch_lag_SWB_CDF[ 24 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) + 2 ] = { + 0, 253, 505, 757, 1008, 1258, 1507, 1755, + 2003, 2249, 2494, 2738, 2982, 3225, 3469, 3713, + 3957, 4202, 4449, 4698, 4949, 5203, 5460, 5720, + 5983, 6251, 6522, 6798, 7077, 7361, 7650, 7942, + 8238, 8539, 8843, 9150, 9461, 9775, 10092, 10411, + 10733, 11057, 11383, 11710, 12039, 12370, 12701, 13034, + 13368, 13703, 14040, 14377, 14716, 15056, 15398, 15742, + 16087, 16435, 16785, 17137, 17492, 17850, 18212, 18577, + 18946, 19318, 19695, 20075, 20460, 20849, 21243, 21640, + 22041, 22447, 22856, 23269, 23684, 24103, 24524, 24947, + 25372, 25798, 26225, 26652, 27079, 27504, 27929, 28352, + 28773, 29191, 29606, 30018, 30427, 30831, 31231, 31627, + 32018, 32404, 32786, 33163, 33535, 33902, 34264, 34621, + 34973, 35320, 35663, 36000, 36333, 36662, 36985, 37304, + 37619, 37929, 38234, 38535, 38831, 39122, 39409, 39692, + 39970, 40244, 40513, 40778, 41039, 41295, 41548, 41796, + 42041, 42282, 42520, 42754, 42985, 43213, 43438, 43660, + 43880, 44097, 44312, 44525, 44736, 44945, 45153, 45359, + 45565, 45769, 45972, 46175, 46377, 46578, 46780, 46981, + 47182, 47383, 47585, 47787, 47989, 48192, 48395, 48599, + 48804, 49009, 49215, 49422, 49630, 49839, 50049, 50259, + 50470, 50682, 50894, 51107, 51320, 51533, 51747, 51961, + 52175, 52388, 52601, 52813, 53025, 53236, 53446, 53655, + 53863, 54069, 54274, 54477, 54679, 54879, 55078, 55274, + 55469, 55662, 55853, 56042, 56230, 56415, 56598, 56779, + 56959, 57136, 57311, 57484, 57654, 57823, 57989, 58152, + 58314, 58473, 58629, 58783, 58935, 59084, 59230, 59373, + 59514, 59652, 59787, 59919, 60048, 60174, 60297, 60417, + 60533, 60647, 60757, 60865, 60969, 61070, 61167, 61262, + 61353, 61442, 61527, 61609, 61689, 61765, 61839, 61910, + 61979, 62045, 62109, 62170, 62230, 62287, 62343, 62396, + 62448, 62498, 62547, 62594, 62640, 62685, 62728, 62770, + 62811, 62852, 62891, 62929, 62967, 63004, 63040, 63075, + 63110, 63145, 63178, 63212, 63244, 63277, 63308, 63340, + 63371, 63402, 63432, 63462, 63491, 63521, 63550, 63578, + 63607, 63635, 63663, 63690, 63718, 63744, 63771, 63798, + 63824, 63850, 63875, 63900, 63925, 63950, 63975, 63999, + 64023, 64046, 64069, 64092, 64115, 64138, 64160, 64182, + 64204, 64225, 64247, 64268, 64289, 64310, 64330, 64351, + 64371, 64391, 64411, 64431, 64450, 64470, 64489, 64508, + 64527, 64545, 64564, 64582, 64600, 64617, 64635, 64652, + 64669, 64686, 64702, 64719, 64735, 64750, 64766, 64782, + 64797, 64812, 64827, 64842, 64857, 64872, 64886, 64901, + 64915, 64930, 64944, 64959, 64974, 64988, 65003, 65018, + 65033, 65048, 65063, 65078, 65094, 65109, 65125, 65141, + 65157, 65172, 65188, 65204, 65220, 65236, 65252, 65268, + 65283, 65299, 65314, 65330, 65345, 65360, 65375, 65390, + 65405, 65419, 65434, 65449, 65463, 65477, 65492, 65506, + 65521, 65535 +}; + +const SKP_int SKP_Silk_pitch_lag_SWB_CDF_offset = 128; + + +const SKP_uint16 SKP_Silk_pitch_contour_CDF[ 35 ] = { + 0, 372, 843, 1315, 1836, 2644, 3576, 4719, + 6088, 7621, 9396, 11509, 14245, 17618, 20777, 24294, + 27992, 33116, 40100, 44329, 47558, 50679, 53130, 55557, + 57510, 59022, 60285, 61345, 62316, 63140, 63762, 64321, + 64729, 65099, 65535 +}; + +const SKP_int SKP_Silk_pitch_contour_CDF_offset = 17; + +const SKP_uint16 SKP_Silk_pitch_delta_CDF[23] = { + 0, 343, 740, 1249, 1889, 2733, 3861, 5396, + 7552, 10890, 16053, 24152, 30220, 34680, 37973, 40405, + 42243, 43708, 44823, 45773, 46462, 47055, 65535 +}; + +const SKP_int SKP_Silk_pitch_delta_CDF_offset = 11; diff --git a/pkg/silk/csilk/SKP_Silk_tables_pulses_per_block.c b/pkg/silk/csilk/SKP_Silk_tables_pulses_per_block.c new file mode 100644 index 0000000..b5803d4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_pulses_per_block.c @@ -0,0 +1,235 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_int SKP_Silk_max_pulses_table[ 4 ] = { + 6, 8, 12, 18 +}; + +const SKP_uint16 SKP_Silk_pulses_per_block_CDF[ 10 ][ 21 ] = +{ +{ + 0, 47113, 61501, 64590, 65125, 65277, 65352, 65407, + 65450, 65474, 65488, 65501, 65508, 65514, 65516, 65520, + 65521, 65523, 65524, 65526, 65535 +}, +{ + 0, 26368, 47760, 58803, 63085, 64567, 65113, 65333, + 65424, 65474, 65498, 65511, 65517, 65520, 65523, 65525, + 65526, 65528, 65529, 65530, 65535 +}, +{ + 0, 9601, 28014, 45877, 57210, 62560, 64611, 65260, + 65447, 65500, 65511, 65519, 65521, 65525, 65526, 65529, + 65530, 65531, 65532, 65534, 65535 +}, +{ + 0, 3351, 12462, 25972, 39782, 50686, 57644, 61525, + 63521, 64506, 65009, 65255, 65375, 65441, 65471, 65488, + 65497, 65505, 65509, 65512, 65535 +}, +{ + 0, 488, 2944, 9295, 19712, 32160, 43976, 53121, + 59144, 62518, 64213, 65016, 65346, 65470, 65511, 65515, + 65525, 65529, 65531, 65534, 65535 +}, +{ + 0, 17013, 30405, 40812, 48142, 53466, 57166, 59845, + 61650, 62873, 63684, 64223, 64575, 64811, 64959, 65051, + 65111, 65143, 65165, 65183, 65535 +}, +{ + 0, 2994, 8323, 15845, 24196, 32300, 39340, 45140, + 49813, 53474, 56349, 58518, 60167, 61397, 62313, 62969, + 63410, 63715, 63906, 64056, 65535 +}, +{ + 0, 88, 721, 2795, 7542, 14888, 24420, 34593, + 43912, 51484, 56962, 60558, 62760, 64037, 64716, 65069, + 65262, 65358, 65398, 65420, 65535 +}, +{ + 0, 287, 789, 2064, 4398, 8174, 13534, 20151, + 27347, 34533, 41295, 47242, 52070, 55772, 58458, 60381, + 61679, 62533, 63109, 63519, 65535 +}, +{ + 0, 1, 3, 91, 4521, 14708, 28329, 41955, + 52116, 58375, 61729, 63534, 64459, 64924, 65092, 65164, + 65182, 65198, 65203, 65211, 65535 +} +}; + +const SKP_int SKP_Silk_pulses_per_block_CDF_offset = 6; + + +const SKP_int16 SKP_Silk_pulses_per_block_BITS_Q6[ 9 ][ 20 ] = +{ +{ + 30, 140, 282, 444, 560, 625, 654, 677, + 731, 780, 787, 844, 859, 960, 896, 1024, + 960, 1024, 960, 821 +}, +{ + 84, 103, 164, 252, 350, 442, 526, 607, + 663, 731, 787, 859, 923, 923, 960, 1024, + 960, 1024, 1024, 875 +}, +{ + 177, 117, 120, 162, 231, 320, 426, 541, + 657, 803, 832, 960, 896, 1024, 923, 1024, + 1024, 1024, 960, 1024 +}, +{ + 275, 182, 146, 144, 166, 207, 261, 322, + 388, 450, 516, 582, 637, 710, 762, 821, + 832, 896, 923, 734 +}, +{ + 452, 303, 216, 170, 153, 158, 182, 220, + 274, 337, 406, 489, 579, 681, 896, 811, + 896, 960, 923, 1024 +}, +{ + 125, 147, 170, 202, 232, 265, 295, 332, + 368, 406, 443, 483, 520, 563, 606, 646, + 704, 739, 757, 483 +}, +{ + 285, 232, 200, 190, 193, 206, 224, 244, + 266, 289, 315, 340, 367, 394, 425, 462, + 496, 539, 561, 350 +}, +{ + 611, 428, 319, 242, 202, 178, 172, 180, + 199, 229, 268, 313, 364, 422, 482, 538, + 603, 683, 739, 586 +}, +{ + 501, 450, 364, 308, 264, 231, 212, 204, + 204, 210, 222, 241, 265, 295, 326, 362, + 401, 437, 469, 321 +} +}; + +const SKP_uint16 SKP_Silk_rate_levels_CDF[ 2 ][ 10 ] = +{ +{ + 0, 2005, 12717, 20281, 31328, 36234, 45816, 57753, + 63104, 65535 +}, +{ + 0, 8553, 23489, 36031, 46295, 53519, 56519, 59151, + 64185, 65535 +} +}; + +const SKP_int SKP_Silk_rate_levels_CDF_offset = 4; + + +const SKP_int16 SKP_Silk_rate_levels_BITS_Q6[ 2 ][ 9 ] = +{ +{ + 322, 167, 199, 164, 239, 178, 157, 231, + 304 +}, +{ + 188, 137, 153, 171, 204, 285, 297, 237, + 358 +} +}; + +const SKP_uint16 SKP_Silk_shell_code_table0[ 33 ] = { + 0, 32748, 65535, 0, 9505, 56230, 65535, 0, + 4093, 32204, 61720, 65535, 0, 2285, 16207, 48750, + 63424, 65535, 0, 1709, 9446, 32026, 55752, 63876, + 65535, 0, 1623, 6986, 21845, 45381, 59147, 64186, + 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table1[ 52 ] = { + 0, 32691, 65535, 0, 12782, 52752, 65535, 0, + 4847, 32665, 60899, 65535, 0, 2500, 17305, 47989, + 63369, 65535, 0, 1843, 10329, 32419, 55433, 64277, + 65535, 0, 1485, 7062, 21465, 43414, 59079, 64623, + 65535, 0, 0, 4841, 14797, 31799, 49667, 61309, + 65535, 65535, 0, 0, 0, 8032, 21695, 41078, + 56317, 65535, 65535, 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table2[ 102 ] = { + 0, 32615, 65535, 0, 14447, 50912, 65535, 0, + 6301, 32587, 59361, 65535, 0, 3038, 18640, 46809, + 62852, 65535, 0, 1746, 10524, 32509, 55273, 64278, + 65535, 0, 1234, 6360, 21259, 43712, 59651, 64805, + 65535, 0, 1020, 4461, 14030, 32286, 51249, 61904, + 65100, 65535, 0, 851, 3435, 10006, 23241, 40797, + 55444, 63009, 65252, 65535, 0, 0, 2075, 7137, + 17119, 31499, 46982, 58723, 63976, 65535, 65535, 0, + 0, 0, 3820, 11572, 23038, 37789, 51969, 61243, + 65535, 65535, 65535, 0, 0, 0, 0, 6882, + 16828, 30444, 44844, 57365, 65535, 65535, 65535, 65535, + 0, 0, 0, 0, 0, 10093, 22963, 38779, + 54426, 65535, 65535, 65535, 65535, 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table3[ 207 ] = { + 0, 32324, 65535, 0, 15328, 49505, 65535, 0, + 7474, 32344, 57955, 65535, 0, 3944, 19450, 45364, + 61873, 65535, 0, 2338, 11698, 32435, 53915, 63734, + 65535, 0, 1506, 7074, 21778, 42972, 58861, 64590, + 65535, 0, 1027, 4490, 14383, 32264, 50980, 61712, + 65043, 65535, 0, 760, 3022, 9696, 23264, 41465, + 56181, 63253, 65251, 65535, 0, 579, 2256, 6873, + 16661, 31951, 48250, 59403, 64198, 65360, 65535, 0, + 464, 1783, 5181, 12269, 24247, 39877, 53490, 61502, + 64591, 65410, 65535, 0, 366, 1332, 3880, 9273, + 18585, 32014, 45928, 56659, 62616, 64899, 65483, 65535, + 0, 286, 1065, 3089, 6969, 14148, 24859, 38274, + 50715, 59078, 63448, 65091, 65481, 65535, 0, 0, + 482, 2010, 5302, 10408, 18988, 30698, 43634, 54233, + 60828, 64119, 65288, 65535, 65535, 0, 0, 0, + 1006, 3531, 7857, 14832, 24543, 36272, 47547, 56883, + 62327, 64746, 65535, 65535, 65535, 0, 0, 0, + 0, 1863, 4950, 10730, 19284, 29397, 41382, 52335, + 59755, 63834, 65535, 65535, 65535, 65535, 0, 0, + 0, 0, 0, 2513, 7290, 14487, 24275, 35312, + 46240, 55841, 62007, 65535, 65535, 65535, 65535, 65535, + 0, 0, 0, 0, 0, 0, 3606, 9573, + 18764, 28667, 40220, 51290, 59924, 65535, 65535, 65535, + 65535, 65535, 65535, 0, 0, 0, 0, 0, + 0, 0, 4879, 13091, 23376, 36061, 49395, 59315, + 65535, 65535, 65535, 65535, 65535, 65535, 65535 +}; + +const SKP_uint16 SKP_Silk_shell_code_table_offsets[ 19 ] = { + 0, 0, 3, 7, 12, 18, 25, 33, + 42, 52, 63, 75, 88, 102, 117, 133, + 150, 168, 187 +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tables_sign.c b/pkg/silk/csilk/SKP_Silk_tables_sign.c new file mode 100644 index 0000000..96fc34d --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_sign.c @@ -0,0 +1,42 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_sign_CDF[ 36 ] = +{ + 37840, 36944, 36251, 35304, + 34715, 35503, 34529, 34296, + 34016, 47659, 44945, 42503, + 40235, 38569, 40254, 37851, + 37243, 36595, 43410, 44121, + 43127, 40978, 38845, 40433, + 38252, 37795, 36637, 59159, + 55630, 51806, 48073, 45036, + 48416, 43857, 42678, 41146, +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tables_type_offset.c b/pkg/silk/csilk/SKP_Silk_tables_type_offset.c new file mode 100644 index 0000000..7effe38 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tables_type_offset.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_tables.h" + +const SKP_uint16 SKP_Silk_type_offset_CDF[ 5 ] = { + 0, 37522, 41030, 44212, 65535 +}; + +const SKP_int SKP_Silk_type_offset_CDF_offset = 2; + + +const SKP_uint16 SKP_Silk_type_offset_joint_CDF[ 4 ][ 5 ] = +{ +{ + 0, 57686, 61230, 62358, 65535 +}, +{ + 0, 18346, 40067, 43659, 65535 +}, +{ + 0, 22694, 24279, 35507, 65535 +}, +{ + 0, 6067, 7215, 13010, 65535 +} +}; + diff --git a/pkg/silk/csilk/SKP_Silk_tuning_parameters.h b/pkg/silk/csilk/SKP_Silk_tuning_parameters.h new file mode 100644 index 0000000..09b96ed --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_tuning_parameters.h @@ -0,0 +1,183 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 SKP_SILK_TUNING_PARAMETERS_H +#define SKP_SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWITH_EXPANSION 0.99f + +/* Threshold used by pitch estimator for early escape */ +#define FIND_PITCH_CORRELATION_THRESHOLD_HC_MODE 0.7f +#define FIND_PITCH_CORRELATION_THRESHOLD_MC_MODE 0.75f +#define FIND_PITCH_CORRELATION_THRESHOLD_LC_MODE 0.8f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis defines: regularization and bandwidth expansion */ +#define FIND_LPC_COND_FAC 2.5e-5f +#define FIND_LPC_CHIRP 0.99995f + +/* LTP analysis defines */ +#define FIND_LTP_COND_FAC 1e-5f +#define LTP_DAMPING 0.01f +#define LTP_SMOOTHING 0.1f + +/* LTP quantization settings */ +#define MU_LTP_QUANT_NB 0.03f +#define MU_LTP_QUANT_MB 0.025f +#define MU_LTP_QUANT_WB 0.02f +#define MU_LTP_QUANT_SWB 0.016f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f + +/* Min and max values for low end of pitch frequency range estimation */ +#define VARIABLE_HP_MIN_FREQ 80.0f +#define VARIABLE_HP_MAX_FREQ 150.0f + +/* Max absolute difference between log2 of pitch frequency and smoother state, to enter the smoother */ +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/***********/ +/* Various */ +/***********/ + +/* Required speech activity for counting frame as active */ +#define WB_DETECT_ACTIVE_SPEECH_LEVEL_THRES 0.7f + +#define SPEECH_ACTIVITY_DTX_THRES 0.1f + +/* Speech Activity LBRR enable threshold (needs tuning) */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.5f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 4.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define SPARSENESS_THRESHOLD_QNT_OFFSET 0.75f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 1e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.95f + +/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */ +#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA 0.01f + +/* gain reduction for fricatives */ +#define DE_ESSER_COEF_SWB_dB 2.0f +#define DE_ESSER_COEF_WB_dB 1.0f + +/* extra harmonic boosting (signal shaping) at low bitrates */ +#define LOW_RATE_HARMONIC_BOOST 0.1f + +/* extra harmonic boosting (signal shaping) for noisy input signals */ +#define LOW_INPUT_QUALITY_HARMONIC_BOOST 0.1f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.3f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 3.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* noise floor to put a lower limit on the quantization step size */ +#define NOISE_FLOOR_dB 4.0f + +/* noise floor relative to active speech gain level */ +#define RELATIVE_MIN_GAIN_dB -50.0f + +/* subframe smoothing coefficient for determining active speech gain level (lower -> more smoothing) */ +#define GAIN_SMOOTHING_COEF 1e-3f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.3f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.2f +#define LAMBDA_CODING_QUALITY -0.1f +#define LAMBDA_QUANT_OFFSET 1.5f + +#ifdef __cplusplus +} +#endif + +#endif // SKP_SILK_TUNING_PARAMETERS_H diff --git a/pkg/silk/csilk/SKP_Silk_typedef.h b/pkg/silk/csilk/SKP_Silk_typedef.h new file mode 100644 index 0000000..5e1d2e7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_typedef.h @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(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 _SKP_SILK_API_TYPDEF_H_ +#define _SKP_SILK_API_TYPDEF_H_ + +#ifndef SKP_USE_DOUBLE_PRECISION_FLOATS +#define SKP_USE_DOUBLE_PRECISION_FLOATS 0 +#endif + +#include +#if defined( __GNUC__ ) +#include +#endif + +#define SKP_int int /* used for counters etc; at least 16 bits */ +#ifdef __GNUC__ +# define SKP_int64 int64_t +#else +# define SKP_int64 long long +#endif +#define SKP_int32 int +#define SKP_int16 short +#define SKP_int8 signed char + +#define SKP_uint unsigned int /* used for counters etc; at least 16 bits */ +#ifdef __GNUC__ +# define SKP_uint64 uint64_t +#else +# define SKP_uint64 unsigned long long +#endif +#define SKP_uint32 unsigned int +#define SKP_uint16 unsigned short +#define SKP_uint8 unsigned char + +#define SKP_int_ptr_size intptr_t + +#if SKP_USE_DOUBLE_PRECISION_FLOATS +# define SKP_float double +# define SKP_float_MAX DBL_MAX +#else +# define SKP_float float +# define SKP_float_MAX FLT_MAX +#endif + +#define SKP_INLINE static __inline + +#ifdef _WIN32 +# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) _stricmp(x, y) +#else +# define SKP_STR_CASEINSENSITIVE_COMPARE(x, y) strcasecmp(x, y) +#endif + +#define SKP_int64_MAX ((SKP_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define SKP_int64_MIN ((SKP_int64)0x8000000000000000LL) /* -2^63 */ +#define SKP_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647*/ +#define SKP_int32_MIN ((SKP_int32)0x80000000) /* -2^31 = -2147483648*/ +#define SKP_int16_MAX 0x7FFF /* 2^15 - 1 = 32767*/ +#define SKP_int16_MIN ((SKP_int16)0x8000) /* -2^15 = -32768*/ +#define SKP_int8_MAX 0x7F /* 2^7 - 1 = 127*/ +#define SKP_int8_MIN ((SKP_int8)0x80) /* -2^7 = -128*/ + +#define SKP_uint32_MAX 0xFFFFFFFF /* 2^32 - 1 = 4294967295 */ +#define SKP_uint32_MIN 0x00000000 +#define SKP_uint16_MAX 0xFFFF /* 2^16 - 1 = 65535 */ +#define SKP_uint16_MIN 0x0000 +#define SKP_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ +#define SKP_uint8_MIN 0x00 + +#define SKP_TRUE 1 +#define SKP_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef SKP_assert +# include /* ASSERTE() */ +# define SKP_assert(COND) _ASSERTE(COND) +# endif +#else +# define SKP_assert(COND) +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c b/pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c new file mode 100644 index 0000000..6adb627 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2012, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, (subject to the limitations in the disclaimer below) +are permitted provided that the following conditions are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must 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 Skype Limited, nor the names of specific +contributors, may be used to endorse or promote products derived from +this software without specific prior written permission. +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED +BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +#define QC 10 +#define QS 14 + + +#if EMBEDDED_ARM<6 +/* Autocorrelations for a warped frequency axis */ +void SKP_Silk_warped_autocorrelation_FIX( + SKP_int32 *corr, /* O Result [order + 1] */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *input, /* I Input data to correlate */ + const SKP_int16 warping_Q16, /* I Warping coefficient */ + const SKP_int length, /* I Length of input */ + const SKP_int order /* I Correlation order (even) */ +) +{ + SKP_int n, i, lsh; + SKP_int32 tmp1_QS, tmp2_QS; + SKP_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + SKP_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + SKP_assert( ( order & 1 ) == 0 ); + SKP_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = SKP_LSHIFT32( ( SKP_int32 )input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = SKP_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += SKP_RSHIFT64( SKP_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = SKP_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += SKP_RSHIFT64( SKP_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += SKP_RSHIFT64( SKP_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = SKP_Silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = SKP_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + SKP_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( SKP_int32 )SKP_CHECK_FIT32( SKP_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( SKP_int32 )SKP_CHECK_FIT32( SKP_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + SKP_assert( corr_QC[ 0 ] >= 0 ); // If breaking, decrease QC +} +#endif + diff --git a/pkg/silk/csilk/skp_silk_sdk.h b/pkg/silk/csilk/skp_silk_sdk.h new file mode 100644 index 0000000..811ed71 --- /dev/null +++ b/pkg/silk/csilk/skp_silk_sdk.h @@ -0,0 +1,11 @@ +#ifndef __SKP_SILK_SDK_H +#define __SKP_SILK_SDK_H + +struct silk_handle; + +struct silk_handle *silk_decoder_init(void); +void silk_decoder_deinit(struct silk_handle *h); +int silk_decoder_process(struct silk_handle *h, unsigned char *frame, int frame_size, unsigned char *output_payload, int output_len); +int silk_decoder_set_sample_rate(struct silk_handle *h, int rate); + +#endif /* __SKP_SILK_SDK_H */ diff --git a/pkg/silk/silk.go b/pkg/silk/silk.go new file mode 100644 index 0000000..9c34607 --- /dev/null +++ b/pkg/silk/silk.go @@ -0,0 +1,122 @@ +package silk + +import ( + "bytes" + "encoding/binary" + "fmt" + "unsafe" +) + +/* +#cgo CFLAGS: -I./csilk/ +#include +#include "skp_silk_sdk.h" +*/ +import "C" + +const ( + MAX_BYTES_PER_FRAME = 1024 + MAX_INPUT_FRAMES = 5 + MAX_FRAME_LENGTH = 480 + FRAME_LENGTH_MS = 20 + MAX_API_FS_KHZ = 48 +) + +type Handle *C.struct_silk_handle + +type Decoder struct { + handle Handle + remainder []byte + closed bool + foundHead bool +} + +func SilkInit() *Decoder { + h := C.silk_decoder_init() + decoder := &Decoder{h, make([]byte, 0), false, false} + + return decoder +} + +func (d *Decoder) SetSampleRate(rate int) { + C.silk_decoder_set_sample_rate(d.handle, C.int(rate)) +} + +func (d *Decoder) Decode(buf []byte) []byte { + d.remainder = append(d.remainder, buf...) + + if len(buf) == 0 || d.closed { + return make([]byte, 0) + } + + if !d.foundHead { + var head []byte + if d.remainder[0] == 0x02 { + head = d.remainder[1:10] + d.remainder = d.remainder[10:] + } else { + head = d.remainder[0:9] + d.remainder = d.remainder[9:] + } + + if string(head) == "#!SILK_V3" { + d.foundHead = true + } else { + fmt.Println("not found head") + return make([]byte, 0) + } + } + + // fmt.Println("remainder:", d.remainder[0:10]) + out := make([]byte, 0) + for { + if len(d.remainder) < 2 { + break + } + buffer := bytes.NewBuffer(d.remainder[0:2]) + // fmt.Println("remainder:", d.remainder[0:2]) + + var nlen int16 + if err := binary.Read(buffer, binary.LittleEndian, &nlen); err != nil { + fmt.Println("Error reading int16:", err) + d.remainder = d.remainder[2:] + return make([]byte, 0) + } + + if nlen <= 0 { + fmt.Println("d.remainder:", d.remainder) + d.remainder = d.remainder[2:] + continue + } + // fmt.Println("nlen:", nlen) + + if len(d.remainder) < (int(nlen) + 2) { + break + } + + frame := d.remainder[2 : 2+nlen] + // fmt.Println("frame:", frame) + payload_len := ((FRAME_LENGTH_MS * MAX_API_FS_KHZ) << 1) * MAX_INPUT_FRAMES + payload := make([]byte, payload_len) + cframe := (*C.uchar)(unsafe.Pointer(&frame[0])) + cpayload := (*C.uchar)(unsafe.Pointer(&payload[0])) + outlen := C.int(C.silk_decoder_process(d.handle, cframe, C.int(nlen), cpayload, C.int(payload_len))) + append_payload := payload[0:outlen] + out = append(out, append_payload...) + d.remainder = d.remainder[2+nlen:] + } + + return out +} + +func (d *Decoder) Close() { + if !d.closed { + d.closed = true + C.silk_decoder_deinit(d.handle) + } +} + +func (d *Decoder) Flush() []byte { + var tmp []byte + return d.Decode(tmp) +} diff --git a/pkg/silk/writer.go b/pkg/silk/writer.go new file mode 100644 index 0000000..fdbf1bc --- /dev/null +++ b/pkg/silk/writer.go @@ -0,0 +1,41 @@ +package silk + +import ( + "io" +) + +type SilkWriter struct { + output io.Writer + Decoder *Decoder + DecodedChunkSize int +} + +func NewWriter(out io.Writer) *SilkWriter { + writer := &SilkWriter{out, SilkInit(), 0} + return writer +} + +func (sw *SilkWriter) Write(p []byte) (int, error) { + // fmt.Println("silk Write len:", len(p)) + out := sw.Decoder.Decode(p) + sw.DecodedChunkSize = len(out) + + if sw.DecodedChunkSize > 0 { + _, err := sw.output.Write(out) + if err != nil { + return 0, err + } + } + + return len(p), nil +} + +func (sw *SilkWriter) Close() error { + out := sw.Decoder.Flush() + if len(out) == 0 { + return nil + } + sw.Decoder.Close() + _, err := sw.output.Write(out) + return err +} diff --git a/pkg/silk/z_link_silk_c.c b/pkg/silk/z_link_silk_c.c new file mode 100644 index 0000000..7d90e89 --- /dev/null +++ b/pkg/silk/z_link_silk_c.c @@ -0,0 +1,111 @@ +#include "./csilk/SKP_Silk_NLSF_MSVQ_decode.c" +#include "./csilk/SKP_Silk_scale_copy_vector16.c" +#include "./csilk/SKP_Silk_NLSF2A.c" +#include "./csilk/SKP_Silk_LTP_scale_ctrl_FIX.c" +#include "./csilk/SKP_Silk_NLSF_VQ_weights_laroia.c" +#include "./csilk/SKP_Silk_encode_parameters.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB0_10.c" +#include "./csilk/SKP_Silk_autocorr.c" +#include "./csilk/SKP_Silk_decode_parameters.c" +#include "./csilk/SKP_Silk_k2a_Q16.c" +#include "./csilk/SKP_Silk_NLSF_stabilize.c" +#include "./csilk/SKP_Silk_decode_pitch.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB1_16.c" +#include "./csilk/SKP_Silk_HP_variable_cutoff_FIX.c" +#include "./csilk/SKP_Silk_apply_sine_window.c" +#include "./csilk/SKP_Silk_decode_core.c" +#include "./csilk/SKP_Silk_resampler_down2_3.c" +#include "./csilk/SKP_Silk_log2lin.c" +#include "./csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c" +#include "./csilk/SKP_Silk_PLC.c" +#include "./csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c" +#include "./csilk/SKP_Silk_quant_LTP_gains_FIX.c" +#include "./csilk/SKP_Silk_array_maxabs.c" +#include "./csilk/SKP_Silk_resampler_private_down_FIR.c" +#include "./csilk/SKP_Silk_tables_other.c" +#include "./csilk/Decoder_Api.c" +#include "./csilk/SKP_Silk_NLSF2A_stable.c" +#include "./csilk/SKP_Silk_find_pitch_lags_FIX.c" +#include "./csilk/SKP_Silk_CNG.c" +#include "./csilk/SKP_Silk_LPC_synthesis_order16.c" +#include "./csilk/SKP_Silk_corrMatrix_FIX.c" +#include "./csilk/SKP_Silk_init_encoder_FIX.c" +#include "./csilk/SKP_Silk_sort.c" +#include "./csilk/SKP_Silk_MA.c" +#include "./csilk/SKP_Silk_process_gains_FIX.c" +#include "./csilk/SKP_Silk_decode_pulses.c" +#include "./csilk/SKP_Silk_find_LTP_FIX.c" +#include "./csilk/SKP_Silk_resampler_private_AR2.c" +#include "./csilk/SKP_Silk_shell_coder.c" +#include "./csilk/SKP_Silk_LP_variable_cutoff.c" +#include "./csilk/SKP_Silk_inner_prod_aligned.c" +#include "./csilk/SKP_Silk_tables_pitch_lag.c" +#include "./csilk/SKP_Silk_warped_autocorrelation_FIX.c" +#include "./csilk/SKP_Silk_tables_LTP.c" +#include "./csilk/SKP_Silk_process_NLSFs_FIX.c" +#include "./csilk/SKP_Silk_ana_filt_bank_1.c" +#include "./csilk/SKP_Silk_NSQ.c" +#include "./csilk/SKP_Silk_biquad.c" +#include "./csilk/SKP_Silk_biquad_alt.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB1_10.c" +#include "./csilk/SKP_Silk_scale_vector.c" +#include "./csilk/SKP_Silk_resampler.c" +#include "./csilk/SKP_Silk_range_coder.c" +#include "./csilk/SKP_Silk_decoder_set_fs.c" +#include "./csilk/SKP_Silk_lin2log.c" +#include "./csilk/SKP_Silk_tables_gain.c" +#include "./csilk/SKP_Silk_k2a.c" +#include "./csilk/SKP_Silk_sum_sqr_shift.c" +#include "./csilk/SKP_Silk_resampler_private_ARMA4.c" +#include "./csilk/SKP_Silk_resampler_private_copy.c" +#include "./csilk/SKP_Silk_resampler_rom.c" +#include "./csilk/SKP_Silk_noise_shape_analysis_FIX.c" +#include "./csilk/SKP_Silk_solve_LS_FIX.c" +#include "./csilk/SKP_Silk_div_oabi.c" +#include "./csilk/SKP_Silk_bwexpander.c" +#include "./csilk/SKP_Silk_find_pred_coefs_FIX.c" +#include "./csilk/SKP_Silk_resampler_down2.c" +#include "./csilk/SKP_Silk_enc_API.c" +#include "./csilk/SKP_Silk_resampler_private_up2_HQ.c" +#include "./csilk/SKP_Silk_resampler_private_up4.c" +#include "./csilk/SKP_Silk_LBRR_reset.c" +#include "./csilk/SKP_Silk_detect_SWB_input.c" +#include "./csilk/SKP_Silk_control_audio_bandwidth.c" +#include "./csilk/SKP_Silk_prefilter_FIX.c" +#include "./csilk/SKP_Silk_find_LPC_FIX.c" +#include "./csilk/SKP_Silk_resampler_up2.c" +#include "./csilk/SKP_Silk_bwexpander_32.c" +#include "./csilk/SKP_Silk_encode_pulses.c" +#include "./csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c" +#include "./csilk/SKP_Silk_tables_pulses_per_block.c" +#include "./csilk/SKP_Silk_control_codec_FIX.c" +#include "./csilk/SKP_Silk_VAD.c" +#include "./csilk/SKP_Silk_NSQ_del_dec.c" +#include "./csilk/SKP_Silk_code_signs.c" +#include "./csilk/SKP_Silk_decode_frame.c" +#include "./csilk/SKP_Silk_burg_modified.c" +#include "./csilk/SKP_Silk_sigm_Q15.c" +#include "./csilk/SKP_Silk_pitch_analysis_core.c" +#include "./csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c" +#include "./csilk/SKP_Silk_interpolate.c" +#include "./csilk/SKP_Silk_LSF_cos_table.c" +#include "./csilk/SKP_Silk_encode_frame_FIX.c" +#include "./csilk/SKP_Silk_resampler_private_IIR_FIR.c" +#include "./csilk/SKP_Silk_schur.c" +#include "./csilk/SKP_Silk_LPC_synthesis_filter.c" +#include "./csilk/SKP_Silk_pitch_est_tables.c" +#include "./csilk/SKP_Silk_A2NLSF.c" +#include "./csilk/SKP_Silk_residual_energy16_FIX.c" +#include "./csilk/SKP_Silk_LPC_inv_pred_gain.c" +#include "./csilk/SKP_Silk_resampler_down3.c" +#include "./csilk/SKP_Silk_schur64.c" +#include "./csilk/SKP_Silk_gain_quant.c" +#include "./csilk/SKP_Silk_residual_energy_FIX.c" +#include "./csilk/SKP_Silk_resampler_private_down4.c" +#include "./csilk/SKP_Silk_create_init_destroy.c" +#include "./csilk/SKP_Silk_regularize_correlations_FIX.c" +#include "./csilk/SKP_Silk_LTP_analysis_filter_FIX.c" +#include "./csilk/SKP_Silk_dec_API.c" +#include "./csilk/SKP_Silk_tables_sign.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB0_16.c" +#include "./csilk/SKP_Silk_tables_type_offset.c" diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go new file mode 100644 index 0000000..c7af718 --- /dev/null +++ b/pkg/utils/utils.go @@ -0,0 +1,77 @@ +package utils + +import ( + "fmt" + "log" + "os" + "os/exec" + "strings" + + "github.com/pkg/browser" + "golang.org/x/sys/windows/registry" +) + +func getDefaultProgram(fileExtension string) (string, error) { + key, err := registry.OpenKey(registry.CLASSES_ROOT, fmt.Sprintf(`.%s`, fileExtension), registry.QUERY_VALUE) + if err != nil { + return "", err + } + defer key.Close() + + // 读取默认程序关联值 + defaultProgram, _, err := key.GetStringValue("") + if err != nil { + return "", err + } + + return defaultProgram, nil +} + +func hasDefaultProgram(fileExtension string) bool { + prog, err := getDefaultProgram(fileExtension) + if err != nil { + log.Println("getDefaultProgram Error:", err) + return false + } + + if prog == "" { + return false + } + + return true +} + +func OpenFileOrExplorer(filePath string, explorer bool) error { + if _, err := os.Stat(filePath); err != nil { + log.Printf("%s %v\n", filePath, err) + return err + } + + canOpen := false + fileExtension := "" + index := strings.LastIndex(filePath, ".") + if index > 0 { + fileExtension = filePath[index+1:] + canOpen = hasDefaultProgram(fileExtension) + } + + if canOpen && !explorer { + return browser.OpenFile(filePath) + } + + commandArgs := []string{"/select,", filePath} + fmt.Println("cmd:", "explorer", commandArgs) + + // 创建一个Cmd结构体表示要执行的命令 + cmd := exec.Command("explorer", commandArgs...) + + // 执行命令并等待它完成 + err := cmd.Run() + if err != nil { + log.Printf("Error executing command: %s\n", err) + // return err + } + + fmt.Println("Command executed successfully") + return nil +} diff --git a/pkg/wechat/msg.pb.go b/pkg/wechat/msg.pb.go new file mode 100644 index 0000000..ab16df5 --- /dev/null +++ b/pkg/wechat/msg.pb.go @@ -0,0 +1,301 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v3.6.1 +// source: msg.proto + +package wechat + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SubMessage1 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"` + Field2 int32 `protobuf:"varint,2,opt,name=field2,proto3" json:"field2,omitempty"` +} + +func (x *SubMessage1) Reset() { + *x = SubMessage1{} + if protoimpl.UnsafeEnabled { + mi := &file_msg_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubMessage1) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubMessage1) ProtoMessage() {} + +func (x *SubMessage1) ProtoReflect() protoreflect.Message { + mi := &file_msg_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubMessage1.ProtoReflect.Descriptor instead. +func (*SubMessage1) Descriptor() ([]byte, []int) { + return file_msg_proto_rawDescGZIP(), []int{0} +} + +func (x *SubMessage1) GetField1() int32 { + if x != nil { + return x.Field1 + } + return 0 +} + +func (x *SubMessage1) GetField2() int32 { + if x != nil { + return x.Field2 + } + return 0 +} + +type SubMessage2 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"` + Field2 string `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"` +} + +func (x *SubMessage2) Reset() { + *x = SubMessage2{} + if protoimpl.UnsafeEnabled { + mi := &file_msg_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubMessage2) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubMessage2) ProtoMessage() {} + +func (x *SubMessage2) ProtoReflect() protoreflect.Message { + mi := &file_msg_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubMessage2.ProtoReflect.Descriptor instead. +func (*SubMessage2) Descriptor() ([]byte, []int) { + return file_msg_proto_rawDescGZIP(), []int{1} +} + +func (x *SubMessage2) GetField1() int32 { + if x != nil { + return x.Field1 + } + return 0 +} + +func (x *SubMessage2) GetField2() string { + if x != nil { + return x.Field2 + } + return "" +} + +type MessageBytesExtra struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message1 *SubMessage1 `protobuf:"bytes,1,opt,name=message1,proto3" json:"message1,omitempty"` + Message2 []*SubMessage2 `protobuf:"bytes,3,rep,name=message2,proto3" json:"message2,omitempty"` +} + +func (x *MessageBytesExtra) Reset() { + *x = MessageBytesExtra{} + if protoimpl.UnsafeEnabled { + mi := &file_msg_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MessageBytesExtra) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageBytesExtra) ProtoMessage() {} + +func (x *MessageBytesExtra) ProtoReflect() protoreflect.Message { + mi := &file_msg_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageBytesExtra.ProtoReflect.Descriptor instead. +func (*MessageBytesExtra) Descriptor() ([]byte, []int) { + return file_msg_proto_rawDescGZIP(), []int{2} +} + +func (x *MessageBytesExtra) GetMessage1() *SubMessage1 { + if x != nil { + return x.Message1 + } + return nil +} + +func (x *MessageBytesExtra) GetMessage2() []*SubMessage2 { + if x != nil { + return x.Message2 + } + return nil +} + +var File_msg_proto protoreflect.FileDescriptor + +var file_msg_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x6d, 0x73, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x61, 0x70, 0x70, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x75, 0x62, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, + 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x12, + 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x45, 0x78, 0x74, 0x72, 0x61, 0x12, 0x35, 0x0a, + 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x75, 0x62, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x31, 0x12, 0x35, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x75, 0x62, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x32, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x42, 0x09, 0x5a, 0x07, 0x2e, + 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_msg_proto_rawDescOnce sync.Once + file_msg_proto_rawDescData = file_msg_proto_rawDesc +) + +func file_msg_proto_rawDescGZIP() []byte { + file_msg_proto_rawDescOnce.Do(func() { + file_msg_proto_rawDescData = protoimpl.X.CompressGZIP(file_msg_proto_rawDescData) + }) + return file_msg_proto_rawDescData +} + +var file_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_msg_proto_goTypes = []interface{}{ + (*SubMessage1)(nil), // 0: app.protobuf.SubMessage1 + (*SubMessage2)(nil), // 1: app.protobuf.SubMessage2 + (*MessageBytesExtra)(nil), // 2: app.protobuf.MessageBytesExtra +} +var file_msg_proto_depIdxs = []int32{ + 0, // 0: app.protobuf.MessageBytesExtra.message1:type_name -> app.protobuf.SubMessage1 + 1, // 1: app.protobuf.MessageBytesExtra.message2:type_name -> app.protobuf.SubMessage2 + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_msg_proto_init() } +func file_msg_proto_init() { + if File_msg_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_msg_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubMessage1); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_msg_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubMessage2); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_msg_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageBytesExtra); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_msg_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_msg_proto_goTypes, + DependencyIndexes: file_msg_proto_depIdxs, + MessageInfos: file_msg_proto_msgTypes, + }.Build() + File_msg_proto = out.File + file_msg_proto_rawDesc = nil + file_msg_proto_goTypes = nil + file_msg_proto_depIdxs = nil +} diff --git a/pkg/wechat/wechat.go b/pkg/wechat/wechat.go new file mode 100644 index 0000000..2815392 --- /dev/null +++ b/pkg/wechat/wechat.go @@ -0,0 +1,653 @@ +package wechat + +import ( + "bufio" + "bytes" + "crypto/hmac" + "crypto/sha1" + "database/sql" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + "wechatDataBackup/pkg/lame" + "wechatDataBackup/pkg/silk" + + _ "github.com/mattn/go-sqlite3" + "github.com/shirou/gopsutil/v3/process" + "golang.org/x/sys/windows" +) + +type WeChatInfo struct { + ProcessID uint32 + FilePath string + AcountName string + Version string + Is64Bits bool + DllBaseAddr uintptr + DllBaseSize uint32 + DBKey string +} + +type wechatMediaMSG struct { + Key string + MsgSvrID int + Buf []byte +} + +func GetWeChatAllInfo() (WeChatInfo, error) { + info, err := GetWeChatInfo() + if err != nil { + log.Println("GetWeChatInfo:", err) + return info, err + } + + info.DBKey = GetWeChatKey(&info) + + return info, nil +} + +func ExportWeChatAllData(info WeChatInfo, expPath string, progress chan<- string) { + defer close(progress) + fileInfo, err := os.Stat(info.FilePath) + if err != nil || !fileInfo.IsDir() { + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s error\"}", info.FilePath) + return + } + if !exportWeChatDateBase(info, expPath, progress) { + return + } + + exportWeChatBat(info, expPath, progress) + exportWeChatVideoAndFile(info, expPath, progress) + exportWeChatVoice(info, expPath, progress) +} + +func exportWeChatVoice(info WeChatInfo, expPath string, progress chan<- string) { + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat voice start\", \"progress\": 61}" + + voicePath := fmt.Sprintf("%s\\FileStorage\\Voice", expPath) + if _, err := os.Stat(voicePath); err != nil { + if err := os.MkdirAll(voicePath, 0644); err != nil { + log.Printf("MkdirAll %s failed: %v\n", voicePath, err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v error\"}", err) + return + } + } + + var wg sync.WaitGroup + index := -1 + MSGChan := make(chan wechatMediaMSG, 100) + go func() { + for { + index += 1 + mediaMSGDB := fmt.Sprintf("%s\\Msg\\Multi\\MediaMSG%d.db", expPath, index) + _, err := os.Stat(mediaMSGDB) + if err != nil { + break + } + + db, err := sql.Open("sqlite3", mediaMSGDB) + if err != nil { + log.Printf("open %s failed: %v\n", mediaMSGDB, err) + continue + } + defer db.Close() + + rows, err := db.Query("select Key, Reserved0, Buf from Media;") + if err != nil { + log.Printf("Query failed: %v\n", err) + continue + } + + msg := wechatMediaMSG{} + for rows.Next() { + err := rows.Scan(&msg.Key, &msg.MsgSvrID, &msg.Buf) + if err != nil { + log.Println("Scan failed: ", err) + break + } + + MSGChan <- msg + } + } + close(MSGChan) + }() + + for i := 0; i < 20; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for msg := range MSGChan { + mp3Path := fmt.Sprintf("%s\\%d.mp3", voicePath, msg.MsgSvrID) + _, err := os.Stat(mp3Path) + if err == nil { + continue + } + + err = silkToMp3(msg.Buf[:], mp3Path) + if err != nil { + log.Printf("silkToMp3 %s failed: %v\n", mp3Path, err) + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat voice end\", \"progress\": 100}" +} + +func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- string) { + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Video and File start\", , \"progress\": 41}" + videoRootPath := info.FilePath + "\\FileStorage\\Video" + fileRootPath := info.FilePath + "\\FileStorage\\File" + cacheRootPath := info.FilePath + "\\FileStorage\\Cache" + rootPaths := []string{videoRootPath, fileRootPath, cacheRootPath} + var wg sync.WaitGroup + taskChan := make(chan [2]string, 100) + go func() { + for _, rootPath := range rootPaths { + log.Println(rootPath) + err := filepath.Walk(rootPath, func(path string, finfo os.FileInfo, err error) error { + if err != nil { + log.Printf("filepath.Walk:%v\n", err) + return err + } + + if !finfo.IsDir() { + expFile := expPath + path[len(info.FilePath):] + _, err := os.Stat(filepath.Dir(expFile)) + if err != nil { + os.MkdirAll(filepath.Dir(expFile), 0644) + } + + _, err = os.Stat(expFile) + if err == nil { + return nil + } + task := [2]string{path, expFile} + taskChan <- task + return nil + } + + return nil + }) + if err != nil { + log.Println("filepath.Walk:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + } + } + close(taskChan) + }() + + for i := 1; i < 30; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + _, err := copyFile(task[0], task[1]) + if err != nil { + log.Println("DecryptDat:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"copyFile %v\"}", err) + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Video and File end\", \"progress\": 60}" +} + +func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) { + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat start\", \"progress\": 21}" + datRootPath := info.FilePath + "\\FileStorage\\MsgAttach" + fileInfo, err := os.Stat(datRootPath) + if err != nil || !fileInfo.IsDir() { + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s error\"}", datRootPath) + return + } + + var wg sync.WaitGroup + taskChan := make(chan [2]string, 100) + go func() { + err = filepath.Walk(datRootPath, func(path string, finfo os.FileInfo, err error) error { + if err != nil { + log.Printf("filepath.Walk:%v\n", err) + return err + } + + if !finfo.IsDir() && strings.HasSuffix(path, ".dat") { + expFile := expPath + path[len(info.FilePath):] + _, err := os.Stat(filepath.Dir(expFile)) + if err != nil { + os.MkdirAll(filepath.Dir(expFile), 0644) + } + + _, err = os.Stat(expFile) + if err == nil { + return nil + } + + task := [2]string{path, expFile} + taskChan <- task + return nil + } + + return nil + }) + + if err != nil { + log.Println("filepath.Walk:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + } + close(taskChan) + }() + + for i := 1; i < 30; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + err = DecryptDat(task[0], task[1]) + if err != nil { + log.Println("DecryptDat:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"DecryptDat %v\"}", err) + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat end\", \"progress\": 40}" +} + +func exportWeChatDateBase(info WeChatInfo, expPath string, progress chan<- string) bool { + + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat DateBase start\", \"progress\": 1}" + + dbKey, err := hex.DecodeString(info.DBKey) + if err != nil { + log.Println("DecodeString:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + return false + } + + var wg sync.WaitGroup + taskChan := make(chan [2]string, 20) + go func() { + err = filepath.Walk(info.FilePath+"\\Msg", func(path string, finfo os.FileInfo, err error) error { + if err != nil { + log.Printf("filepath.Walk:%v\n", err) + return err + } + if !finfo.IsDir() && strings.HasSuffix(path, ".db") { + expFile := expPath + path[len(info.FilePath):] + _, err := os.Stat(filepath.Dir(expFile)) + if err != nil { + os.MkdirAll(filepath.Dir(expFile), 0644) + } + + task := [2]string{path, expFile} + taskChan <- task + } + + return nil + }) + if err != nil { + log.Println("filepath.Walk:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + } + close(taskChan) + }() + + for i := 1; i < 20; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + if filepath.Base(task[0]) == "xInfo.db" { + copyFile(task[0], task[1]) + } else { + err = DecryptDataBase(task[0], dbKey, task[1]) + if err != nil { + log.Println("DecryptDataBase:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s %v\"}", task[0], err) + } + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat DateBase end\", \"progress\": 20}" + return true +} + +func GetWeChatInfo() (info WeChatInfo, rerr error) { + info = WeChatInfo{} + processes, err := process.Processes() + if err != nil { + log.Println("Error getting processes:", err) + rerr = err + return + } + + found := false + for _, p := range processes { + name, err := p.Name() + if err != nil { + continue + } + if name == "WeChat.exe" { + found = true + info.ProcessID = uint32(p.Pid) + info.Is64Bits, _ = Is64BitProcess(info.ProcessID) + log.Println("ProcessID", info.ProcessID) + files, err := p.OpenFiles() + if err != nil { + log.Println("OpenFiles failed") + return + } + + for _, f := range files { + if strings.HasSuffix(f.Path, "\\Media.db") { + // fmt.Printf("opened %s\n", f.Path[4:]) + filePath := f.Path[4:] + parts := strings.Split(filePath, string(filepath.Separator)) + if len(parts) < 4 { + return info, errors.New("Error filePath " + filePath) + } + info.FilePath = strings.Join(parts[:len(parts)-2], string(filepath.Separator)) + info.AcountName = strings.Join(parts[len(parts)-3:len(parts)-2], string(filepath.Separator)) + } + + } + + if len(info.FilePath) == 0 { + rerr = errors.New("wechat not log in") + return + } + + hModuleSnap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE|windows.TH32CS_SNAPMODULE32, uint32(p.Pid)) + if err != nil { + log.Println("CreateToolhelp32Snapshot failed", err) + return + } + defer windows.CloseHandle(hModuleSnap) + + var me32 windows.ModuleEntry32 + me32.Size = uint32(windows.SizeofModuleEntry32) + + err = windows.Module32First(hModuleSnap, &me32) + if err != nil { + log.Println("Module32First failed", err) + return + } + + for ; err == nil; err = windows.Module32Next(hModuleSnap, &me32) { + if windows.UTF16ToString(me32.Module[:]) == "WeChatWin.dll" { + // fmt.Printf("MODULE NAME: %s\n", windows.UTF16ToString(me32.Module[:])) + // fmt.Printf("executable NAME: %s\n", windows.UTF16ToString(me32.ExePath[:])) + // fmt.Printf("base address: 0x%08X\n", me32.ModBaseAddr) + // fmt.Printf("base ModBaseSize: %d\n", me32.ModBaseSize) + info.DllBaseAddr = me32.ModBaseAddr + info.DllBaseSize = me32.ModBaseSize + + var zero windows.Handle + driverPath := windows.UTF16ToString(me32.ExePath[:]) + infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero) + if err != nil { + log.Println("GetFileVersionInfoSize failed", err) + return + } + versionInfo := make([]byte, infoSize) + if err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])); err != nil { + log.Println("GetFileVersionInfo failed", err) + return + } + var fixedInfo *windows.VS_FIXEDFILEINFO + fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo)) + err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen) + if err != nil { + log.Println("VerQueryValue failed", err) + return + } + // fmt.Printf("%s: v%d.%d.%d.%d\n", windows.UTF16ToString(me32.Module[:]), + // (fixedInfo.FileVersionMS>>16)&0xff, + // (fixedInfo.FileVersionMS>>0)&0xff, + // (fixedInfo.FileVersionLS>>16)&0xff, + // (fixedInfo.FileVersionLS>>0)&0xff) + + info.Version = fmt.Sprintf("%d.%d.%d.%d", + (fixedInfo.FileVersionMS>>16)&0xff, + (fixedInfo.FileVersionMS>>0)&0xff, + (fixedInfo.FileVersionLS>>16)&0xff, + (fixedInfo.FileVersionLS>>0)&0xff) + break + } + } + } + } + + if !found { + rerr = errors.New("not found process") + } + + return +} + +func Is64BitProcess(pid uint32) (bool, error) { + is64Bit := false + handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid) + if err != nil { + log.Println("Error opening process:", err) + return is64Bit, errors.New("OpenProcess failed") + } + defer windows.CloseHandle(handle) + + err = windows.IsWow64Process(handle, &is64Bit) + if err != nil { + log.Println("Error IsWow64Process:", err) + } + return !is64Bit, err +} + +func GetWeChatKey(info *WeChatInfo) string { + handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, uint32(info.ProcessID)) + if err != nil { + log.Println("Error opening process:", err) + return "" + } + defer windows.CloseHandle(handle) + + buffer := make([]byte, info.DllBaseSize) + err = windows.ReadProcessMemory(handle, uintptr(info.DllBaseAddr), &buffer[0], uintptr(len(buffer)), nil) + if err != nil { + log.Println("Error ReadProcessMemory:", err) + return "" + } + + offset := 0 + // searchStr := []byte(info.AcountName) + for { + index := hasDeviceSybmol(buffer[offset:]) + if index == -1 { + fmt.Println("hasDeviceSybmolxxxx") + break + } + fmt.Printf("hasDeviceSybmol: 0x%X\n", index) + keys := findDBKeyPtr(buffer[offset:index], info.Is64Bits) + // fmt.Println("keys:", keys) + + key, err := findDBkey(handle, info.FilePath+"\\Msg\\Media.db", keys) + if err == nil { + // fmt.Println("key:", key) + return key + } + + offset += (index + 20) + } + + return "" +} + +func hasDeviceSybmol(buffer []byte) int { + sybmols := [...][]byte{ + {'a', 'n', 'd', 'r', 'o', 'i', 'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00}, + {'i', 'p', 'h', 'o', 'n', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00}, + {'i', 'p', 'a', 'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, + } + for _, syb := range sybmols { + if index := bytes.Index(buffer, syb); index != -1 { + return index + } + } + + return -1 +} + +func findDBKeyPtr(buffer []byte, is64Bits bool) [][]byte { + keys := make([][]byte, 0) + step := 8 + keyLen := []byte{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + if !is64Bits { + keyLen = keyLen[:4] + step = 4 + } + + offset := len(buffer) - step + for { + if bytes.Contains(buffer[offset:offset+step], keyLen) { + keys = append(keys, buffer[offset-step:offset]) + } + + offset -= step + if offset <= 0 { + break + } + } + + return keys +} + +func findDBkey(handle windows.Handle, path string, keys [][]byte) (string, error) { + var keyAddrPtr uint64 + addrBuffer := make([]byte, 0x08) + for _, key := range keys { + copy(addrBuffer, key) + err := binary.Read(bytes.NewReader(addrBuffer), binary.LittleEndian, &keyAddrPtr) + if err != nil { + log.Println("binary.Read:", err) + continue + } + if keyAddrPtr == 0x00 { + continue + } + log.Println("keyAddrPtr: 0x%X\n", keyAddrPtr) + keyBuffer := make([]byte, 0x20) + err = windows.ReadProcessMemory(handle, uintptr(keyAddrPtr), &keyBuffer[0], uintptr(len(keyBuffer)), nil) + if err != nil { + // fmt.Println("Error ReadProcessMemory:", err) + continue + } + if checkDataBaseKey(path, keyBuffer) { + return hex.EncodeToString(keyBuffer), nil + } + } + + return "", errors.New("not found key") +} + +func checkDataBaseKey(path string, password []byte) bool { + fp, err := os.Open(path) + if err != nil { + return false + } + defer fp.Close() + + fpReader := bufio.NewReaderSize(fp, defaultPageSize*100) + + buffer := make([]byte, defaultPageSize) + + n, err := fpReader.Read(buffer) + if err != nil && n != defaultPageSize { + log.Println("read failed:", err, n) + return false + } + + salt := buffer[:16] + key := pbkdf2HMAC(password, salt, defaultIter, keySize) + + page1 := buffer[16:defaultPageSize] + + macSalt := xorBytes(salt, 0x3a) + macKey := pbkdf2HMAC(key, macSalt, 2, keySize) + + hashMac := hmac.New(sha1.New, macKey) + hashMac.Write(page1[:len(page1)-32]) + hashMac.Write([]byte{1, 0, 0, 0}) + + return hmac.Equal(hashMac.Sum(nil), page1[len(page1)-32:len(page1)-12]) +} + +func (info WeChatInfo) String() string { + return fmt.Sprintf("PID: %d\nVersion: v%s\nBaseAddr: 0x%08X\nDllSize: %d\nIs 64Bits: %v\nFilePath %s\nAcountName: %s", + info.ProcessID, info.Version, info.DllBaseAddr, info.DllBaseSize, info.Is64Bits, info.FilePath, info.AcountName) +} + +func copyFile(src, dst string) (int64, error) { + sourceFile, err := os.Open(src) + if err != nil { + return 0, err + } + defer sourceFile.Close() + + destFile, err := os.Create(dst) + if err != nil { + return 0, err + } + defer destFile.Close() + + bytesWritten, err := io.Copy(destFile, sourceFile) + if err != nil { + return bytesWritten, err + } + + return bytesWritten, nil +} + +func silkToMp3(amrBuf []byte, mp3Path string) error { + amrReader := bytes.NewReader(amrBuf) + + var pcmBuffer bytes.Buffer + sr := silk.NewWriter(&pcmBuffer) + sr.Decoder.SetSampleRate(24000) + amrReader.WriteTo(sr) + sr.Close() + + if pcmBuffer.Len() == 0 { + return errors.New("silk to mp3 failed " + mp3Path) + } + + of, err := os.Create(mp3Path) + if err != nil { + return nil + } + defer of.Close() + + wr := lame.NewWriter(of) + wr.Encoder.SetInSamplerate(24000) + wr.Encoder.SetNumChannels(1) + wr.Encoder.SetBitrate(16) + wr.Encoder.SetQuality(7) + // IMPORTANT! + wr.Encoder.InitParams() + + pcmBuffer.WriteTo(wr) + wr.Close() + + return nil +} diff --git a/pkg/wechat/wechatDBDec.go b/pkg/wechat/wechatDBDec.go new file mode 100644 index 0000000..5c1a708 --- /dev/null +++ b/pkg/wechat/wechatDBDec.go @@ -0,0 +1,170 @@ +package wechat + +import ( + "bufio" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha1" + "fmt" + "io" + "os" +) + +const ( + keySize = 32 + defaultIter = 64000 + defaultPageSize = 4096 +) + +func DecryptDataBase(path string, password []byte, expPath string) error { + sqliteFileHeader := []byte("SQLite format 3") + sqliteFileHeader = append(sqliteFileHeader, byte(0)) + + fp, err := os.Open(path) + if err != nil { + return err + } + defer fp.Close() + + fpReader := bufio.NewReaderSize(fp, defaultPageSize*100) + // fpReader := bufio.NewReader(fp) + + buffer := make([]byte, defaultPageSize) + + n, err := fpReader.Read(buffer) + if err != nil && n != defaultPageSize { + return fmt.Errorf("read failed") + } + + salt := buffer[:16] + key := pbkdf2HMAC(password, salt, defaultIter, keySize) + + page1 := buffer[16:defaultPageSize] + + macSalt := xorBytes(salt, 0x3a) + macKey := pbkdf2HMAC(key, macSalt, 2, keySize) + + hashMac := hmac.New(sha1.New, macKey) + hashMac.Write(page1[:len(page1)-32]) + hashMac.Write([]byte{1, 0, 0, 0}) + + if !hmac.Equal(hashMac.Sum(nil), page1[len(page1)-32:len(page1)-12]) { + return fmt.Errorf("incorrect password") + } + + outFilePath := expPath + outFile, err := os.Create(outFilePath) + if err != nil { + return err + } + defer outFile.Close() + + // Write SQLite file header + _, err = outFile.Write(sqliteFileHeader) + if err != nil { + return err + } + + block, err := aes.NewCipher(key) + if err != nil { + return err + } + + page1 = buffer[16:defaultPageSize] + iv := page1[len(page1)-48 : len(page1)-32] + stream := cipher.NewCBCDecrypter(block, iv) + decrypted := make([]byte, len(page1)-48) + stream.CryptBlocks(decrypted, page1[:len(page1)-48]) + _, err = outFile.Write(decrypted) + if err != nil { + return err + } + _, err = outFile.Write(page1[len(page1)-48:]) + if err != nil { + return err + } + + for { + n, err = fpReader.Read(buffer) + if err != nil { + if err == io.EOF { + break + } + return err + } else if n < defaultPageSize { + return fmt.Errorf("read data to short %d", n) + } + + iv := buffer[len(buffer)-48 : len(buffer)-32] + stream := cipher.NewCBCDecrypter(block, iv) + decrypted := make([]byte, len(buffer)-48) + stream.CryptBlocks(decrypted, buffer[:len(buffer)-48]) + _, err = outFile.Write(decrypted) + if err != nil { + return err + } + _, err = outFile.Write(buffer[len(buffer)-48:]) + if err != nil { + return err + } + } + + return nil +} + +func pbkdf2HMAC(password, salt []byte, iter, keyLen int) []byte { + dk := make([]byte, keyLen) + loop := (keyLen + sha1.Size - 1) / sha1.Size + key := make([]byte, 0, len(salt)+4) + u := make([]byte, sha1.Size) + for i := 1; i <= loop; i++ { + key = key[:0] + key = append(key, salt...) + key = append(key, byte(i>>24), byte(i>>16), byte(i>>8), byte(i)) + hmac := hmac.New(sha1.New, password) + hmac.Write(key) + digest := hmac.Sum(nil) + copy(u, digest) + for j := 2; j <= iter; j++ { + hmac.Reset() + hmac.Write(digest) + digest = hmac.Sum(digest[:0]) + for k, di := range digest { + u[k] ^= di + } + } + copy(dk[(i-1)*sha1.Size:], u) + } + return dk +} + +func xorBytes(a []byte, b byte) []byte { + result := make([]byte, len(a)) + for i := range a { + result[i] = a[i] ^ b + } + return result +} + +/* +func main() { + + str := "82b1a210335140a1bc8a57397391186494abe666595b4f408095538b5518f7d5" + // 将十六进制字符串解码为字节 + password, err := hex.DecodeString(str) + if err != nil { + fmt.Println("解码出错:", err) + return + } + + fmt.Println(hex.EncodeToString(password)) + + err = decryptMsg("Media.db", password) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Println("Decryption successful!") + } +} +*/ diff --git a/pkg/wechat/wechatDataProvider.go b/pkg/wechat/wechatDataProvider.go new file mode 100644 index 0000000..086daf7 --- /dev/null +++ b/pkg/wechat/wechatDataProvider.go @@ -0,0 +1,878 @@ +package wechat + +import ( + "database/sql" + "encoding/xml" + "errors" + "fmt" + "log" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + sync "sync" + "time" + + "github.com/beevik/etree" + _ "github.com/mattn/go-sqlite3" + "github.com/pierrec/lz4" + "google.golang.org/protobuf/proto" +) + +const ( + Wechat_Message_Type_Text = 1 + Wechat_Message_Type_Picture = 3 + Wechat_Message_Type_Voice = 34 + Wechat_Message_Type_Video = 43 + Wechat_Message_Type_Emoji = 47 + Wechat_Message_Type_Misc = 49 + Wechat_Message_Type_System = 10000 +) + +const ( + Wechat_Misc_Message_TEXT = 1 + Wechat_Misc_Message_CardLink = 5 + Wechat_Misc_Message_File = 6 + Wechat_Misc_Message_CustomEmoji = 8 + Wechat_Misc_Message_ForwardMessage = 19 + Wechat_Misc_Message_Applet = 33 + Wechat_Misc_Message_Applet2 = 36 + Wechat_Misc_Message_Refer = 57 + Wechat_Misc_Message_Live = 63 + Wechat_Misc_Message_Notice = 87 + Wechat_Misc_Message_Live2 = 88 + Wechat_Misc_Message_Transfer = 2000 + Wechat_Misc_Message_RedPacket = 2003 +) + +const ( + Wechat_System_Message_Notice = 1 + Wechat_System_Message_Tickle = 4 + Wechat_System_Message_Notice2 = 8000 +) + +type Message_Search_Direction int + +const ( + Message_Search_Forward Message_Search_Direction = iota + Message_Search_Backward + Message_Search_Both +) + +type WeChatUserInfo struct { + UserName string `json:"UserName"` + Alias string `json:"Alias"` + ReMark string `json:"ReMark"` + NickName string `json:"NickName"` + SmallHeadImgUrl string `json:"SmallHeadImgUrl"` + BigHeadImgUrl string `json:"BigHeadImgUrl"` +} + +type WeChatSession struct { + UserName string `json:"UserName"` + NickName string `json:"NickName"` + Content string `json:"Content"` + UserInfo WeChatUserInfo `json:"UserInfo"` + Time uint64 `json:"Time"` + IsGroup bool `json:IsGroup` +} + +type WeChatSessionList struct { + Total int `json:"Total"` + Rows []WeChatSession `json:"Rows"` +} + +type FileInfo struct { + FileName string `json:"fileName"` + FileSize string `json:"fileSize"` + FilePath string `json:"filePath"` + FileExt string `json:"fileExt"` +} + +type LinkInfo struct { + Url string `json:"Url"` + Title string `json:"Title"` + Description string `json:"Description"` + DisPlayName string `json:"DisPlayName"` +} + +type ReferInfo struct { + Type int `json:"Type"` + SubType int `json:"SubType"` + Svrid int64 `json:"Svrid"` + Displayname string `json:"Displayname"` + Content string `json:"Content"` +} + +type WeChatMessage struct { + LocalId int `json:"LocalId"` + MsgSvrId int64 `json:"MsgSvrId"` + Type int `json:"type"` + SubType int `json:"SubType"` + IsSender int `json:"IsSender"` + CreateTime int64 `json:"createTime"` + Talker string `json:"talker"` + Content string `json:"content"` + ThumbPath string `json:"ThumbPath"` + ImagePath string `json:"ImagePath"` + VideoPath string `json:"VideoPath"` + FileInfo FileInfo `json:"fileInfo"` + EmojiPath string `json:"EmojiPath"` + VoicePath string `json:"VoicePath"` + IsChatRoom bool `json:"isChatRoom"` + UserInfo WeChatUserInfo `json:"userInfo"` + LinkInfo LinkInfo `json:"LinkInfo"` + ReferInfo ReferInfo `json:"ReferInfo"` + compressContent []byte + bytesExtra []byte +} + +type WeChatMessageList struct { + KeyWord string `json:"KeyWord"` + Total int `json:"Total"` + Rows []WeChatMessage `json:"Rows"` +} + +type WeChatMessageDate struct { + Date []string `json:"Date"` + Total int `json:"Total"` +} + +type WeChatUserList struct { + Users []WeChatUserInfo `json:"Users"` + Total int `json:"Total"` +} + +type wechatMsgDB struct { + path string + db *sql.DB + startTime int64 + endTime int64 +} + +type WechatDataProvider struct { + resPath string + microMsg *sql.DB + + msgDBs []*wechatMsgDB + userInfoMap map[string]WeChatUserInfo + userInfoMtx sync.Mutex + + SelfInfo *WeChatUserInfo +} + +const ( + MicroMsgDB = "MicroMsg.db" +) + +type byTime []*wechatMsgDB + +func (a byTime) Len() int { return len(a) } +func (a byTime) Less(i, j int) bool { return a[i].startTime > a[j].startTime } +func (a byTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func CreateWechatDataProvider(resPath string) (*WechatDataProvider, error) { + provider := &WechatDataProvider{} + provider.resPath = resPath + provider.msgDBs = make([]*wechatMsgDB, 0) + log.Println(resPath) + userName := filepath.Base(resPath) + MicroMsgDBPath := resPath + "\\Msg\\" + MicroMsgDB + microMsg, err := sql.Open("sqlite3", MicroMsgDBPath) + if err != nil { + log.Printf("open db %s error: %v", MicroMsgDBPath, err) + return provider, err + } + + index := 0 + for { + msgDBPath := fmt.Sprintf("%s\\Msg\\Multi\\MSG%d.db", provider.resPath, index) + if _, err := os.Stat(msgDBPath); err != nil { + log.Println("msgDBPath end", msgDBPath) + break + } + + msgDB, err := wechatOpenMsgDB(msgDBPath) + if err != nil { + log.Printf("open db %s error: %v", msgDBPath, err) + break + } + provider.msgDBs = append(provider.msgDBs, msgDB) + log.Printf("MSG%d.db start %d - %d end\n", index, msgDB.startTime, msgDB.endTime) + index += 1 + } + sort.Sort(byTime(provider.msgDBs)) + for _, db := range provider.msgDBs { + log.Printf("%s start %d - %d end\n", db.path, db.startTime, db.endTime) + } + provider.userInfoMap = make(map[string]WeChatUserInfo) + provider.microMsg = microMsg + provider.SelfInfo, err = provider.WechatGetUserInfoByName(userName) + if err != nil { + log.Printf("WechatGetUserInfoByName %s failed: %v", userName, err) + return provider, err + } + provider.userInfoMap[userName] = *provider.SelfInfo + log.Println("resPath:", provider.resPath) + return provider, nil +} + +func (P *WechatDataProvider) WechatWechatDataProviderClose() { + if P.microMsg != nil { + P.microMsg.Close() + } + + for _, db := range P.msgDBs { + db.db.Close() + } + log.Println("WechatWechatDataProviderClose") +} + +func (P *WechatDataProvider) WechatGetUserInfoByName(name string) (*WeChatUserInfo, error) { + info := &WeChatUserInfo{} + + var UserName, Alias, ReMark, NickName string + querySql := fmt.Sprintf("select ifnull(UserName,'') as UserName, ifnull(Alias,'') as Alias, ifnull(ReMark,'') as ReMark, ifnull(NickName,'') as NickName from Contact where UserName='%s';", name) + // log.Println(querySql) + err := P.microMsg.QueryRow(querySql).Scan(&UserName, &Alias, &ReMark, &NickName) + if err != nil { + log.Println("not found User:", err) + return info, err + } + + log.Printf("UserName %s, Alias %s, ReMark %s, NickName %s\n", UserName, Alias, ReMark, NickName) + + var smallHeadImgUrl, bigHeadImgUrl string + querySql = fmt.Sprintf("select ifnull(smallHeadImgUrl,'') as smallHeadImgUrl, ifnull(bigHeadImgUrl,'') as bigHeadImgUrl from ContactHeadImgUrl where usrName='%s';", UserName) + // log.Println(querySql) + err = P.microMsg.QueryRow(querySql).Scan(&smallHeadImgUrl, &bigHeadImgUrl) + if err != nil { + log.Println("not find headimg", err) + } + + info.UserName = UserName + info.Alias = Alias + info.ReMark = ReMark + info.NickName = NickName + info.SmallHeadImgUrl = smallHeadImgUrl + info.BigHeadImgUrl = bigHeadImgUrl + + // log.Println(info) + return info, nil +} + +func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (*WeChatSessionList, error) { + List := &WeChatSessionList{} + List.Rows = make([]WeChatSession, 0) + + querySql := fmt.Sprintf("select ifnull(strUsrName,'') as strUsrName,ifnull(strNickName,'') as strNickName,ifnull(strContent,'') as strContent, nTime from Session order by rowid desc limit %d, %d;", pageIndex*pageSize, pageSize) + dbRows, err := P.microMsg.Query(querySql) + if err != nil { + log.Println(err) + return List, err + } + defer dbRows.Close() + + var strUsrName, strNickName, strContent string + var nTime uint64 + for dbRows.Next() { + var session WeChatSession + err = dbRows.Scan(&strUsrName, &strNickName, &strContent, &nTime) + if err != nil { + log.Println(err) + continue + } + if len(strContent) == 0 { + log.Printf("%s cotent nil\n", strUsrName) + continue + } + + session.UserName = strUsrName + session.NickName = strNickName + session.Content = strContent + session.Time = nTime + session.IsGroup = strings.HasSuffix(strUsrName, "@chatroom") + info, err := P.WechatGetUserInfoByName(strUsrName) + if err != nil { + log.Printf("WechatGetUserInfoByName %s failed\n", strUsrName) + continue + } + session.UserInfo = *info + List.Rows = append(List.Rows, session) + List.Total += 1 + } + + return List, nil +} + +func (P *WechatDataProvider) WeChatGetMessageListByTime(userName string, time int64, pageSize int, direction Message_Search_Direction) (*WeChatMessageList, error) { + + List := &WeChatMessageList{} + List.Rows = make([]WeChatMessage, 0) + selectTime := time + selectpageSize := pageSize + + if direction == Message_Search_Both { + selectpageSize = pageSize / 2 + } + for direction == Message_Search_Forward || direction == Message_Search_Both { + selectList, err := P.weChatGetMessageListByTime(userName, selectTime, selectpageSize, Message_Search_Forward) + if err != nil { + return List, err + } + + if selectList.Total == 0 { + break + } + + selectTime = selectList.Rows[selectList.Total-1].CreateTime - 1 + selectpageSize -= selectList.Total + List.Total += selectList.Total + List.Rows = append(List.Rows, selectList.Rows...) + if selectpageSize <= 0 { + break + } + log.Printf("Forward selectTime %d, selectpageSize %d\n", selectTime, selectpageSize) + } + + selectTime = time + if direction == Message_Search_Both { + selectpageSize = pageSize / 2 + } + for direction == Message_Search_Backward || direction == Message_Search_Both { + selectList, err := P.weChatGetMessageListByTime(userName, selectTime, selectpageSize, Message_Search_Backward) + if err != nil { + return List, err + } + + if selectList.Total == 0 { + break + } + + selectTime = selectList.Rows[0].CreateTime + 1 + selectpageSize -= selectList.Total + List.Total += selectList.Total + List.Rows = append(selectList.Rows, List.Rows...) + if selectpageSize <= 0 { + break + } + log.Printf("Backward selectTime %d, selectpageSize %d\n", selectTime, selectpageSize) + } + + return List, nil +} + +func (P *WechatDataProvider) weChatGetMessageListByTime(userName string, time int64, pageSize int, direction Message_Search_Direction) (*WeChatMessageList, error) { + List := &WeChatMessageList{} + List.Rows = make([]WeChatMessage, 0) + index := P.wechatFindDBIndex(userName, time, direction) + if index == -1 { + log.Printf("Not found %s %d data\n", userName, time) + return List, nil + } + + sqlFormat := "select localId,MsgSvrID,Type,SubType,IsSender,CreateTime,ifnull(StrTalker,'') as StrTalker, ifnull(StrContent,'') as StrContent,ifnull(CompressContent,'') as CompressContent,ifnull(BytesExtra,'') as BytesExtra from MSG Where StrTalker='%s' And CreateTime<=%d order by CreateTime desc limit %d;" + if direction == Message_Search_Backward { + sqlFormat = "select localId,MsgSvrID,Type,SubType,IsSender,CreateTime,ifnull(StrTalker,'') as StrTalker, ifnull(StrContent,'') as StrContent,ifnull(CompressContent,'') as CompressContent,ifnull(BytesExtra,'') as BytesExtra from ( select localId, MsgSvrID, Type, SubType, IsSender, CreateTime, StrTalker, StrContent, CompressContent, BytesExtra FROM MSG Where StrTalker='%s' And CreateTime>%d order by CreateTime asc limit %d) AS SubQuery order by CreateTime desc;" + } + querySql := fmt.Sprintf(sqlFormat, userName, time, pageSize) + log.Println(querySql) + + rows, err := P.msgDBs[index].db.Query(querySql) + if err != nil { + log.Printf("%s failed %v\n", querySql, err) + return List, nil + } + defer rows.Close() + var localId, Type, SubType, IsSender int + var MsgSvrID, CreateTime int64 + var StrTalker, StrContent string + var CompressContent, BytesExtra []byte + + for rows.Next() { + message := WeChatMessage{} + err = rows.Scan(&localId, &MsgSvrID, &Type, &SubType, &IsSender, &CreateTime, + &StrTalker, &StrContent, &CompressContent, &BytesExtra) + if err != nil { + log.Println("rows.Scan failed", err) + return List, err + } + message.LocalId = localId + message.MsgSvrId = MsgSvrID + message.Type = Type + message.SubType = SubType + message.IsSender = IsSender + message.CreateTime = CreateTime + message.Talker = StrTalker + message.Content = StrContent + message.IsChatRoom = strings.HasSuffix(StrTalker, "@chatroom") + message.compressContent = make([]byte, len(CompressContent)) + message.bytesExtra = make([]byte, len(BytesExtra)) + copy(message.compressContent, CompressContent) + copy(message.bytesExtra, BytesExtra) + P.wechatMessageExtraHandle(&message) + P.wechatMessageGetUserInfo(&message) + P.wechatMessageEmojiHandle(&message) + P.wechatMessageCompressContentHandle(&message) + List.Rows = append(List.Rows, message) + List.Total += 1 + } + + if err := rows.Err(); err != nil { + log.Println("rows.Scan failed", err) + return List, err + } + + return List, nil +} + +func (P *WechatDataProvider) WeChatGetMessageListByKeyWord(userName string, time int64, keyWord string, msgType string, pageSize int) (*WeChatMessageList, error) { + List := &WeChatMessageList{} + List.Rows = make([]WeChatMessage, 0) + List.KeyWord = keyWord + _time := time + selectPagesize := pageSize + if keyWord != "" || msgType != "" { + selectPagesize = 600 + } + for { + log.Println("time:", _time, keyWord) + rawList, err := P.weChatGetMessageListByTime(userName, _time, selectPagesize, Message_Search_Forward) + if err != nil { + log.Println("weChatGetMessageListByTime failed: ", err) + return nil, err + } + log.Println("rawList.Total:", rawList.Total) + if rawList.Total == 0 { + if List.Total == 0 { + log.Printf("user %s not find [%s]\n", userName, keyWord) + } + break + } + + for i, _ := range rawList.Rows { + if weChatMessageTypeFilter(&rawList.Rows[i], msgType) && (len(keyWord) == 0 || weChatMessageContains(&rawList.Rows[i], keyWord)) { + List.Rows = append(List.Rows, rawList.Rows[i]) + List.Total += 1 + if List.Total >= pageSize { + return List, nil + } + } + } + + _time = rawList.Rows[rawList.Total-1].CreateTime - 1 + } + + return List, nil +} + +func (P *WechatDataProvider) WeChatGetMessageDate(userName string) (*WeChatMessageDate, error) { + messageData := &WeChatMessageDate{} + messageData.Date = make([]string, 0) + messageData.Total = 0 + + _time := time.Now().Unix() + + for { + index := P.wechatFindDBIndex(userName, _time, Message_Search_Forward) + if index == -1 { + log.Println("wechat find db end") + return messageData, nil + } + + sqlFormat := " SELECT DISTINCT strftime('%%Y-%%m-%%d', datetime(CreateTime+28800, 'unixepoch')) FROM MSG WHERE StrTalker='%s' order by CreateTime desc;" + querySql := fmt.Sprintf(sqlFormat, userName) + + rows, err := P.msgDBs[index].db.Query(querySql) + if err != nil { + log.Printf("%s failed %v\n", querySql, err) + return messageData, nil + } + defer rows.Close() + + var date string + for rows.Next() { + err = rows.Scan(&date) + if err != nil { + log.Println("rows.Scan failed", err) + return messageData, err + } + + messageData.Date = append(messageData.Date, date) + messageData.Total += 1 + } + + if err := rows.Err(); err != nil { + log.Println("rows.Scan failed", err) + return messageData, err + } + + _time = P.wechatGetLastMessageCreateTime(userName, index) + if -1 == _time { + log.Println("wechatGetLastMessageCreateTime failed") + return messageData, errors.New("wechatGetLastMessageCreateTime failed") + } + + _time -= 1 + } +} + +func (P *WechatDataProvider) WeChatGetChatRoomUserList(chatroom string) (*WeChatUserList, error) { + userList := &WeChatUserList{} + userList.Users = make([]WeChatUserInfo, 0) + userList.Total = 0 + + sqlFormat := "select UserNameList from ChatRoom where ChatRoomName='%s';" + querySql := fmt.Sprintf(sqlFormat, chatroom) + + var userNameListStr string + err := P.microMsg.QueryRow(querySql).Scan(&userNameListStr) + if err != nil { + log.Println("Scan: ", err) + return nil, err + } + + userNameArray := strings.Split(userNameListStr, "^G") + log.Println("userNameArray:", userNameArray) + + for _, userName := range userNameArray { + pinfo, err := P.WechatGetUserInfoByNameOnCache(userName) + if err == nil { + userList.Users = append(userList.Users, *pinfo) + userList.Total += 1 + } + } + + return userList, nil +} + +func (info WeChatUserInfo) String() string { + return fmt.Sprintf("NickName:[%s] Alias:[%s], NickName:[%s], ReMark:[%s], SmallHeadImgUrl:[%s], BigHeadImgUrl[%s]", + info.NickName, info.Alias, info.NickName, info.ReMark, info.SmallHeadImgUrl, info.BigHeadImgUrl) +} + +func (P *WechatDataProvider) wechatMessageExtraHandle(msg *WeChatMessage) { + var extra MessageBytesExtra + err := proto.Unmarshal(msg.bytesExtra, &extra) + if err != nil { + log.Println("proto.Unmarshal failed", err) + return + } + + for _, ext := range extra.Message2 { + switch ext.Field1 { + case 1: + if msg.IsChatRoom { + msg.Talker = ext.Field2 + } + case 3: + if len(ext.Field2) > 0 && (msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video || msg.Type == Wechat_Message_Type_Misc) { + msg.ThumbPath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + } + case 4: + if len(ext.Field2) > 0 { + if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_File { + msg.FileInfo.FilePath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + msg.FileInfo.FileName = filepath.Base(ext.Field2) + } else if msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video || msg.Type == Wechat_Message_Type_Misc { + msg.ImagePath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + msg.VideoPath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + } + } + } + } + + if msg.Type == Wechat_Message_Type_Voice { + msg.VoicePath = fmt.Sprintf("%s\\FileStorage\\Voice\\%d.mp3", P.resPath, msg.MsgSvrId) + } +} + +type EmojiMsg struct { + XMLName xml.Name `xml:"msg"` + Emoji Emoji `xml:"emoji"` +} + +type Emoji struct { + XMLName xml.Name `xml:"emoji"` + CdnURL string `xml:"cdnurl,attr"` + Thumburl string `xml:"thumburl,attr"` + Width string `xml:"width,attr"` + Height string `xml:"height,attr"` +} + +func (P *WechatDataProvider) wechatMessageEmojiHandle(msg *WeChatMessage) { + if msg.Type != Wechat_Message_Type_Emoji { + return + } + + emojiMsg := EmojiMsg{} + err := xml.Unmarshal([]byte(msg.Content), &emojiMsg) + if err != nil { + log.Println("xml.Unmarshal failed: ", err, msg.Content) + return + } + + msg.EmojiPath = emojiMsg.Emoji.CdnURL +} + +type xmlDocument struct { + *etree.Document +} + +func NewxmlDocument(e *etree.Document) *xmlDocument { + return &xmlDocument{e} +} + +func (e *xmlDocument) FindElementValue(path string) string { + item := e.FindElement(path) + if item != nil { + return item.Text() + } + + return "" +} + +func (P *WechatDataProvider) wechatMessageCompressContentHandle(msg *WeChatMessage) { + if len(msg.compressContent) == 0 { + return + } + + unCompressContent := make([]byte, len(msg.compressContent)*10) + ulen, err := lz4.UncompressBlock(msg.compressContent, unCompressContent) + if err != nil { + log.Println("UncompressBlock failed:", err, msg.MsgSvrId) + return + } + + compMsg := etree.NewDocument() + if err := compMsg.ReadFromBytes(unCompressContent[:ulen-1]); err != nil { + // os.WriteFile("D:\\tmp\\"+string(msg.LocalId)+".xml", unCompressContent[:ulen], 0600) + log.Println("ReadFromBytes failed:", err) + return + } + + root := NewxmlDocument(compMsg) + if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_CardLink { + msg.LinkInfo.Title = root.FindElementValue("/msg/appmsg/title") + msg.LinkInfo.Description = root.FindElementValue("/msg/appmsg/des") + msg.LinkInfo.Url = root.FindElementValue("/msg/appmsg/url") + msg.LinkInfo.DisPlayName = root.FindElementValue("/msg/appmsg/sourcedisplayname") + appName := root.FindElementValue("/msg/appinfo/appname") + if len(msg.LinkInfo.DisPlayName) == 0 && len(appName) > 0 { + msg.LinkInfo.DisPlayName = appName + } + } else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Refer { + msg.Content = root.FindElementValue("/msg/appmsg/title") + msg.ReferInfo.Type, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/refermsg/type")) + msg.ReferInfo.Svrid, _ = strconv.ParseInt(root.FindElementValue("/msg/appmsg/refermsg/svrid"), 10, 64) + msg.ReferInfo.Displayname = root.FindElementValue("/msg/appmsg/refermsg/displayname") + msg.ReferInfo.Content = root.FindElementValue("/msg/appmsg/refermsg/content") + + if msg.ReferInfo.Type == Wechat_Message_Type_Misc { + contentXML := etree.NewDocument() + if err := contentXML.ReadFromString(msg.ReferInfo.Content); err != nil { + log.Println("ReadFromString failed:", err) + return + } + + root := NewxmlDocument(contentXML) + msg.ReferInfo.Content = root.FindElementValue("/msg/appmsg/title") + msg.ReferInfo.SubType, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/type")) + } + } +} + +func (P *WechatDataProvider) wechatMessageGetUserInfo(msg *WeChatMessage) { + who := msg.Talker + if msg.IsSender == 1 { + who = P.SelfInfo.UserName + } + + pinfo, err := P.WechatGetUserInfoByNameOnCache(who) + if err != nil { + log.Println("WechatGetUserInfoByNameOnCache:", err) + return + } + + msg.UserInfo = *pinfo +} + +func (P *WechatDataProvider) wechatFindDBIndex(userName string, time int64, direction Message_Search_Direction) int { + if direction == Message_Search_Forward { + index := 0 + for { + if index >= len(P.msgDBs) { + return -1 + } + msgDB := P.msgDBs[index] + + if msgDB.startTime > time { + index += 1 + continue + } + + rowId := 0 + querySql := fmt.Sprintf("select rowid from Name2ID where UsrName='%s';", userName) + err := msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index += 1 + continue + } + + querySql = fmt.Sprintf(" select rowid from MSG where StrTalker='%s' AND CreateTime<=%d limit 1;", userName, time) + log.Printf("in %s, %s\n", msgDB.path, querySql) + err = msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index += 1 + continue + } + + log.Printf("Select in %d %s\n", index, msgDB.path) + return index + } + } else { + index := len(P.msgDBs) - 1 + for { + if index < 0 { + return -1 + } + msgDB := P.msgDBs[index] + + if msgDB.endTime < time { + index -= 1 + continue + } + + rowId := 0 + querySql := fmt.Sprintf("select rowid from Name2ID where UsrName='%s';", userName) + err := msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index -= 1 + continue + } + + querySql = fmt.Sprintf(" select rowid from MSG where StrTalker='%s' AND CreateTime>%d limit 1;", userName, time) + log.Printf("in %s, %s\n", msgDB.path, querySql) + err = msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index -= 1 + continue + } + + log.Printf("Select in %d %s\n", index, msgDB.path) + return index + } + } +} + +func (P *WechatDataProvider) wechatGetLastMessageCreateTime(userName string, index int) int64 { + if index >= len(P.msgDBs) { + return -1 + } + sqlFormat := "SELECT CreateTime FROM MSG WHERE StrTalker='%s' order by CreateTime asc limit 1;" + querySql := fmt.Sprintf(sqlFormat, userName) + var lastTime int64 + err := P.msgDBs[index].db.QueryRow(querySql).Scan(&lastTime) + if err != nil { + log.Println("select DB lastTime failed:", index, ":", err) + return -1 + } + + return lastTime +} + +func weChatMessageContains(msg *WeChatMessage, chars string) bool { + + switch msg.Type { + case Wechat_Message_Type_Text: + return strings.Contains(msg.Content, chars) + case Wechat_Message_Type_Misc: + switch msg.SubType { + case Wechat_Misc_Message_CardLink: + return strings.Contains(msg.LinkInfo.Title, chars) || strings.Contains(msg.LinkInfo.Description, chars) + case Wechat_Misc_Message_Refer: + return strings.Contains(msg.Content, chars) + case Wechat_Misc_Message_File: + return strings.Contains(msg.FileInfo.FileName, chars) + default: + return false + } + default: + return false + } +} + +func weChatMessageTypeFilter(msg *WeChatMessage, msgType string) bool { + switch msgType { + case "": + return true + case "文件": + return msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_File + case "图片与视频": + return msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video + case "链接": + return msg.Type == Wechat_Misc_Message_CardLink || msg.SubType == Wechat_Misc_Message_CardLink + default: + if strings.HasPrefix(msgType, "群成员") { + userName := msgType[len("群成员"):] + return msg.UserInfo.UserName == userName + } + + return false + } +} + +func wechatOpenMsgDB(path string) (*wechatMsgDB, error) { + msgDB := wechatMsgDB{} + + db, err := sql.Open("sqlite3", path) + if err != nil { + log.Printf("open db %s error: %v", path, err) + return nil, err + } + msgDB.db = db + msgDB.path = path + querySql := "select CreateTime from MSG order by CreateTime asc limit 1;" + err = msgDB.db.QueryRow(querySql).Scan(&msgDB.startTime) + if err != nil { + log.Println("select DB startTime failed:", path, ":", err) + return nil, err + } + + querySql = "select CreateTime from MSG order by CreateTime desc limit 1;" + err = msgDB.db.QueryRow(querySql).Scan(&msgDB.endTime) + if err != nil { + log.Println("select DB endTime failed:", path, ":", err) + return nil, err + } + + return &msgDB, nil +} + +func (P *WechatDataProvider) WechatGetUserInfoByNameOnCache(name string) (*WeChatUserInfo, error) { + + // log.Printf("who: %s", who) + + P.userInfoMtx.Lock() + defer P.userInfoMtx.Unlock() + + info, ok := P.userInfoMap[name] + if ok { + return &info, nil + } + + pinfo, err := P.WechatGetUserInfoByName(name) + if err != nil { + log.Printf("WechatGetUserInfoByName %s failed: %v\n", name, err) + return nil, err + } + + P.userInfoMap[name] = *pinfo + + return pinfo, nil +} diff --git a/pkg/wechat/wechatIMGDec.go b/pkg/wechat/wechatIMGDec.go new file mode 100644 index 0000000..5f246e5 --- /dev/null +++ b/pkg/wechat/wechatIMGDec.go @@ -0,0 +1,209 @@ +package wechat + +import ( + "bufio" + "encoding/hex" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "sync" + "time" +) + +/* + from: https://github.com/liuggchen/wechatDatDecode.git +*/ + +var imagePrefixBtsMap = make(map[string][]byte) + +func DecryptDatByDir(inDir, outDir string) error { + + startTime := time.Now() + f, er := os.Open(inDir) + if er != nil { + fmt.Println(er.Error()) + return er + } + readdir, er := f.Readdir(0) + if er != nil { + fmt.Println(er.Error()) + } + + if stat, er := os.Stat(outDir); os.IsNotExist(er) { + er := os.MkdirAll(outDir, 0755) + if er != nil { + return er + } + } else if !stat.IsDir() { + return errors.New(outDir + "is file") + } + + var taskChan = make(chan os.FileInfo, 100) + + go func() { + for _, info := range readdir { + taskChan <- info + } + close(taskChan) + }() + + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for info := range taskChan { + handlerOne(info, inDir, outDir) + } + }() + } + + wg.Wait() + t := time.Since(startTime).Seconds() + log.Printf("\nfinished time= %v s\n", t) + + return nil +} + +func DecryptDat(inFile string, outFile string) error { + + sourceFile, err := os.Open(inFile) + if err != nil { + log.Println(err.Error()) + return err + } + + var preTenBts = make([]byte, 10) + _, _ = sourceFile.Read(preTenBts) + decodeByte, _, er := findDecodeByte(preTenBts) + if er != nil { + log.Println(er.Error()) + return err + } + + distFile, er := os.Create(outFile) + if er != nil { + log.Println(er.Error()) + return err + } + writer := bufio.NewWriter(distFile) + _, _ = sourceFile.Seek(0, 0) + var rBts = make([]byte, 1024) + for { + n, er := sourceFile.Read(rBts) + if er != nil { + if er == io.EOF { + break + } + log.Println("error: ", er.Error()) + return err + } + for i := 0; i < n; i++ { + _ = writer.WriteByte(rBts[i] ^ decodeByte) + } + } + _ = writer.Flush() + _ = distFile.Close() + _ = sourceFile.Close() + // fmt.Println("output file:", distFile.Name()) + + return nil +} + +func handlerOne(info os.FileInfo, dir string, outputDir string) { + if info.IsDir() || filepath.Ext(info.Name()) != ".dat" { + return + } + fmt.Println("find file: ", info.Name()) + fPath := dir + "/" + info.Name() + sourceFile, err := os.Open(fPath) + if err != nil { + fmt.Println(err.Error()) + return + } + + var preTenBts = make([]byte, 10) + _, _ = sourceFile.Read(preTenBts) + decodeByte, _, er := findDecodeByte(preTenBts) + if er != nil { + fmt.Println(er.Error()) + return + } + + distFile, er := os.Create(outputDir + "/" + info.Name()) + if er != nil { + fmt.Println(er.Error()) + return + } + writer := bufio.NewWriter(distFile) + _, _ = sourceFile.Seek(0, 0) + var rBts = make([]byte, 1024) + for { + n, er := sourceFile.Read(rBts) + if er != nil { + if er == io.EOF { + break + } + fmt.Println("error: ", er.Error()) + return + } + for i := 0; i < n; i++ { + _ = writer.WriteByte(rBts[i] ^ decodeByte) + } + } + _ = writer.Flush() + _ = distFile.Close() + + fmt.Println("output file:", distFile.Name()) +} + +func init() { + //JPEG (jpg),文件头:FFD8FF + //PNG (png),文件头:89504E47 + //GIF (gif),文件头:47494638 + //TIFF (tif),文件头:49492A00 + //Windows Bitmap (bmp),文件头:424D + const ( + Jpeg = "FFD8FF" + Png = "89504E47" + Gif = "47494638" + Tif = "49492A00" + Bmp = "424D" + ) + JpegPrefixBytes, _ := hex.DecodeString(Jpeg) + PngPrefixBytes, _ := hex.DecodeString(Png) + GifPrefixBytes, _ := hex.DecodeString(Gif) + TifPrefixBytes, _ := hex.DecodeString(Tif) + BmpPrefixBytes, _ := hex.DecodeString(Bmp) + + imagePrefixBtsMap = map[string][]byte{ + ".jpeg": JpegPrefixBytes, + ".png": PngPrefixBytes, + ".gif": GifPrefixBytes, + ".tif": TifPrefixBytes, + ".bmp": BmpPrefixBytes, + } +} + +func findDecodeByte(bts []byte) (byte, string, error) { + for ext, prefixBytes := range imagePrefixBtsMap { + deCodeByte, err := testPrefix(prefixBytes, bts) + if err == nil { + return deCodeByte, ext, err + } + } + return 0, "", errors.New("decode fail") +} + +func testPrefix(prefixBytes []byte, bts []byte) (deCodeByte byte, error error) { + var initDecodeByte = prefixBytes[0] ^ bts[0] + for i, prefixByte := range prefixBytes { + if b := prefixByte ^ bts[i]; b != initDecodeByte { + return 0, errors.New("no") + } + } + return initDecodeByte, nil +} diff --git a/res/result.png b/res/result.png new file mode 100644 index 0000000..3044ff3 Binary files /dev/null and b/res/result.png differ diff --git a/res/tips.png b/res/tips.png new file mode 100644 index 0000000..a774247 Binary files /dev/null and b/res/tips.png differ diff --git a/wails.json b/wails.json new file mode 100644 index 0000000..52d9021 --- /dev/null +++ b/wails.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://wails.io/schemas/config.v2.json", + "name": "wechatDataBackup", + "outputfilename": "wechatDataBackup", + "frontend:install": "", + "frontend:build": "", + "frontend:dev:watcher": "", + "frontend:dev:serverUrl": "", + "author": { + "name": "hal", + "email": "1174221722@qq.com" + } +}